diff --git a/.circleci/build.sh b/.circleci/build.sh index 0c311956178..345e209873f 100755 --- a/.circleci/build.sh +++ b/.circleci/build.sh @@ -47,7 +47,7 @@ sccache --show-stats source $XLA_DIR/xla_env export GCLOUD_SERVICE_KEY_FILE="$XLA_DIR/default_credentials.json" -export SILO_NAME='cache-silo-ci' # cache bucket for CI +export SILO_NAME='cache-silo-ci-gcc-11' # cache bucket for CI build_torch_xla $XLA_DIR popd diff --git a/.circleci/common.sh b/.circleci/common.sh index f4d840f87d8..5e9a7ef4585 100755 --- a/.circleci/common.sh +++ b/.circleci/common.sh @@ -92,6 +92,22 @@ function install_deps_pytorch_xla() { sudo ln -s "$(command -v bazelisk)" /usr/bin/bazel + # Install gcc-11 + sudo apt-get update + # Update ppa for GCC + sudo apt-get install -y software-properties-common + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + sudo apt update -y + sudo apt install -y gcc-11 + sudo apt install -y g++-11 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100 + + export NVCC_PREPEND_FLAGS='-ccbin /usr/bin/g++-11' + + # Hack similar to https://github.com/pytorch/pytorch/pull/105227/files#diff-9e59213240d3b55d2ddc53c8c096db9eece0665d64f46473454f9dc0c10fd804 + sudo rm /opt/conda/lib/libstdc++.so* + # Symnlink the missing cuda headers if exists CUBLAS_PATTERN="/usr/include/cublas*" if ls $CUBLAS_PATTERN 1> /dev/null 2>&1; then diff --git a/.circleci/test.sh b/.circleci/test.sh index 1de91774343..914d56d206f 100755 --- a/.circleci/test.sh +++ b/.circleci/test.sh @@ -26,5 +26,5 @@ function install_torchvision() { install_torchvision export GCLOUD_SERVICE_KEY_FILE="$XLA_DIR/default_credentials.json" -export SILO_NAME='cache-silo-ci' # cache bucket for CI +export SILO_NAME='cache-silo-ci-gcc-11' # cache bucket for CI run_torch_xla_tests $PYTORCH_DIR $XLA_DIR $USE_COVERAGE diff --git a/WORKSPACE b/WORKSPACE index ea11667f4ca..9dcd29c45d6 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -38,7 +38,6 @@ http_archive( ], patch_tool = "patch", patches = [ - "//openxla_patches:absl_statusor.diff", "//openxla_patches:cache_urls.diff", "//openxla_patches:cuda_graph.diff", "//openxla_patches:f16_abi_clang.diff", diff --git a/openxla_patches/absl_statusor.diff b/openxla_patches/absl_statusor.diff deleted file mode 100644 index 8b0214356fe..00000000000 --- a/openxla_patches/absl_statusor.diff +++ /dev/null @@ -1,765 +0,0 @@ -Revert 0946f40bab84fb3f23648eb2544c7a46fd9e0700 -diff --git a/xla/BUILD b/xla/BUILD -index ee654c2a1..3939e8b5c 100644 ---- a/xla/BUILD -+++ b/xla/BUILD -@@ -773,7 +773,6 @@ cc_library( - visibility = ["//visibility:public"], - deps = [ - "@com_google_absl//absl/container:flat_hash_map", -- "@com_google_absl//absl/status:statusor", - ], - ) - -diff --git a/xla/executable_run_options.h b/xla/executable_run_options.h -index 31ba23bf3..a24c6a0e3 100644 ---- a/xla/executable_run_options.h -+++ b/xla/executable_run_options.h -@@ -22,7 +22,6 @@ limitations under the License. - #include - - #include "absl/container/flat_hash_map.h" --#include "absl/status/statusor.h" - - // These classes are forward declared so that ExecutableRunOptions can be linked - // into an XLA-compiled binary without having to link all of the pointed-to -@@ -42,11 +41,15 @@ struct ThreadPoolDevice; - - namespace tsl { - template -+class StatusOr; -+template - class AsyncValueRef; - } // namespace tsl - - namespace xla { - -+using ::tsl::StatusOr; // TENSORFLOW_STATUS_OK -+ - class DeviceAssignment; - class ExecutionProfile; - class Shape; -@@ -96,7 +99,7 @@ using ThenExecuteFunction = - // copied from the `src` memory. `frontend_attrs` contains frontend specific - // attributes for the send. - using SendDeviceMemoryFunction = -- std::function>( -+ std::function>( - int64_t channel_id, stream_executor::Stream* stream, const Shape& shape, - const stream_executor::DeviceMemoryBase& src, - const absl::flat_hash_map& frontend_attrs)>; -@@ -106,7 +109,7 @@ using SendDeviceMemoryFunction = - // copied into the `dst` memory. `frontend_attrs` contains frontend specific - // attributes for the receive. - using RecvDeviceMemoryFunction = -- std::function>( -+ std::function>( - int64_t channel_id, stream_executor::Stream* stream, const Shape& shape, - stream_executor::DeviceMemoryBase* dst, - const absl::flat_hash_map& frontend_attrs)>; -diff --git a/third_party/tsl/tools/def_file_filter/def_file_filter.py.tpl b/third_party/tsl/tools/def_file_filter/def_file_filter.py.tpl -index 4c396b485..33cb5f5f0 100644 ---- a/third_party/tsl/tools/def_file_filter/def_file_filter.py.tpl -+++ b/third_party/tsl/tools/def_file_filter/def_file_filter.py.tpl -@@ -54,9 +54,6 @@ INCLUDEPRE_RE = re.compile(r"absl::lts_[0-9]+::base_internal::ThrowStdOutOfRange - r"absl::lts_[0-9]+::Status::UnrefNonInlined|" # for absl::Status - r"absl::lts_[0-9]+::Status::Status|" # for absl::Status - r"absl::lts_[0-9]+::Status::ForEachPayload|" # for absl::Status -- r"absl::lts_[0-9]+::internal_statusor::Helper::Crash|" # for absl::StatusOr -- r"absl::lts_[0-9]+::internal_statusor::Helper::HandleInvalidStatusCtorArg|" -- r"absl::lts_[0-9]+::internal_statusor::ThrowBadStatusOrAccess|" - r"absl::lts_[0-9]+::Cord|" # for tensorflow::Status - r"absl::lts_[0-9]+::Cord::DestroyCordSlow|" # for tensorflow::Status - r"absl::lts_[0-9]+::cord_internal::CordzInfo::MaybeTrackCordImpl" # tensorflow::Status usage of absl::Cord -diff --git a/third_party/tsl/tsl/platform/BUILD b/third_party/tsl/tsl/platform/BUILD -index f261322c8..a6e70c652 100644 ---- a/third_party/tsl/tsl/platform/BUILD -+++ b/third_party/tsl/tsl/platform/BUILD -@@ -311,6 +311,10 @@ cc_library( - - cc_library( - name = "statusor", -+ srcs = [ -+ "statusor.cc", -+ "statusor_internals.h", -+ ], - hdrs = ["statusor.h"], - deps = [ - ":errors", -@@ -318,7 +322,6 @@ cc_library( - ":macros", - ":status", - "@com_google_absl//absl/base:core_headers", -- "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", - "@com_google_absl//absl/types:span", -@@ -549,7 +552,9 @@ filegroup( - "stacktrace.h", - "status.cc", - "status.h", -+ "statusor.cc", - "statusor.h", -+ "statusor_internals.h", - "str_util.cc", - "str_util.h", - "strcat.cc", -@@ -1365,7 +1370,6 @@ tsl_cc_test( - ":test", - ":test_benchmark", - ":test_main", -- "@com_google_absl//absl/base:config", - ], - ) - -diff --git a/third_party/tsl/tsl/platform/errors.h b/third_party/tsl/tsl/platform/errors.h -index 5ec647c3e..f1fcea11d 100644 ---- a/third_party/tsl/tsl/platform/errors.h -+++ b/third_party/tsl/tsl/platform/errors.h -@@ -21,7 +21,6 @@ limitations under the License. - #include - #include - #include --#include - - #include "absl/base/attributes.h" - #include "absl/status/status.h" -diff --git a/third_party/tsl/tsl/platform/status_matchers_test.cc b/third_party/tsl/tsl/platform/status_matchers_test.cc -index 70fc61911..09f288108 100644 ---- a/third_party/tsl/tsl/platform/status_matchers_test.cc -+++ b/third_party/tsl/tsl/platform/status_matchers_test.cc -@@ -118,8 +118,8 @@ TEST(IsOkAndHoldsTest, DescribeExpectedValue) { - TEST(IsOkAndHoldsTest, ExplainNotMatchingStatus) { - Matcher> is_ok_and_less_than = IsOkAndHolds(LessThan(100)); - StatusOr status = errors::Unknown("Unknown"); -- EXPECT_THAT(ExplainMatch(is_ok_and_less_than, status), -- HasSubstr("which has status UNKNOWN: Unknown")); -+ EXPECT_EQ(ExplainMatch(is_ok_and_less_than, status), -+ "which has status " + PrintToString(status)); - } - - TEST(IsOkAndHoldsTest, ExplainNotMatchingValue) { -diff --git a/third_party/tsl/tsl/platform/statusor.cc b/third_party/tsl/tsl/platform/statusor.cc -new file mode 100644 -index 000000000..3dcb01637 ---- /dev/null -+++ b/third_party/tsl/tsl/platform/statusor.cc -@@ -0,0 +1,38 @@ -+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. -+ -+Licensed under the Apache License, Version 2.0 (the "License"); -+you may not use this file except in compliance with the License. -+You may obtain a copy of the License at -+ -+ http://www.apache.org/licenses/LICENSE-2.0 -+ -+Unless required by applicable law or agreed to in writing, software -+distributed under the License is distributed on an "AS IS" BASIS, -+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+See the License for the specific language governing permissions and -+limitations under the License. -+==============================================================================*/ -+ -+#include "tsl/platform/statusor.h" -+ -+#include "tsl/platform/errors.h" -+#include "tsl/platform/logging.h" -+ -+namespace tsl { -+namespace internal_statusor { -+ -+void Helper::HandleInvalidStatusCtorArg(Status* status) { -+ const char* kMessage = -+ "An OK status is not a valid constructor argument to StatusOr"; -+ LOG(ERROR) << kMessage; -+ // Fall back to tsl::error::INTERNAL. -+ *status = ::tsl::errors::Internal(kMessage); -+} -+ -+void Helper::Crash(const Status& status) { -+ LOG(FATAL) << "Attempting to fetch value instead of handling error " -+ << status; -+} -+ -+} // namespace internal_statusor -+} // namespace tsl -\ No newline at end of file -diff --git a/third_party/tsl/tsl/platform/statusor.h b/third_party/tsl/tsl/platform/statusor.h -index b627208e3..a480cb761 100644 ---- a/third_party/tsl/tsl/platform/statusor.h -+++ b/third_party/tsl/tsl/platform/statusor.h -@@ -69,14 +69,312 @@ limitations under the License. - #define TENSORFLOW_TSL_PLATFORM_STATUSOR_H_ - - #include "absl/base/attributes.h" --#include "absl/status/statusor.h" - #include "tsl/platform/errors.h" - #include "tsl/platform/macros.h" - #include "tsl/platform/status.h" -+#include "tsl/platform/statusor_internals.h" - - namespace tsl { - --using absl::StatusOr; -+#if TF_HAS_CPP_ATTRIBUTE(nodiscard) -+template -+class [[nodiscard]] StatusOr; -+#endif -+ -+template -+class StatusOr : private internal_statusor::StatusOrData, -+ private internal_statusor::TraitsBase< -+ std::is_copy_constructible::value, -+ std::is_move_constructible::value> { -+ template -+ friend class StatusOr; -+ -+ typedef internal_statusor::StatusOrData Base; -+ -+ public: -+ typedef T element_type; // DEPRECATED: use `value_type`. -+ typedef T value_type; -+ -+ // Constructs a new StatusOr with Status::UNKNOWN status. This is marked -+ // 'explicit' to try to catch cases like 'return {};', where people think -+ // StatusOr> will be initialized with an empty vector, -+ // instead of a Status::UNKNOWN status. -+ explicit StatusOr(); -+ -+ // StatusOr will be copy constructible/assignable if T is copy -+ // constructible. -+ StatusOr(const StatusOr&) = default; -+ StatusOr& operator=(const StatusOr&) = default; -+ -+ // StatusOr will be move constructible/assignable if T is move -+ // constructible. -+ StatusOr(StatusOr&&) = default; -+ StatusOr& operator=(StatusOr&&) = default; -+ -+ // Conversion copy/move constructor, T must be convertible from U. -+ template ::value>::type* = nullptr> -+ StatusOr(const StatusOr& other); -+ template ::value>::type* = nullptr> -+ StatusOr(StatusOr&& other); -+ -+ // Conversion copy/move assignment operator, T must be convertible from U. -+ template ::value>::type* = nullptr> -+ StatusOr& operator=(const StatusOr& other); -+ template ::value>::type* = nullptr> -+ StatusOr& operator=(StatusOr&& other); -+ -+ // Constructs the inner value `T` in-place using the provided args, using the -+ // `T(args...)` constructor. -+ template -+ explicit StatusOr(absl::in_place_t, Args&&... args); -+ -+ // Constructs a new StatusOr with the given value. After calling this -+ // constructor, calls to value() will succeed, and calls to status() will -+ // return OK. -+ // -+ // NOTE: Not explicit - we want to use StatusOr as a return type -+ // so it is convenient and sensible to be able to do 'return T()' -+ // when the return type is StatusOr. -+ // -+ // REQUIRES: T is copy constructible. -+ StatusOr(const T& value); -+ -+ // Constructs a new StatusOr with the given non-ok status. After calling -+ // this constructor, calls to value() will CHECK-fail. -+ // -+ // NOTE: Not explicit - we want to use StatusOr as a return -+ // value, so it is convenient and sensible to be able to do 'return -+ // Status()' when the return type is StatusOr. -+ // -+ // REQUIRES: !status.ok(). This requirement is DCHECKed. -+ // In optimized builds, passing OkStatus() here will have the effect -+ // of passing tsl::error::INTERNAL as a fallback. -+ StatusOr(const Status& status); -+ StatusOr& operator=(const Status& status); -+ -+ // TODO(b/62186997): Add operator=(T) overloads. -+ -+ // Similar to the `const T&` overload. -+ // -+ // REQUIRES: T is move constructible. -+ StatusOr(T&& value); -+ -+ // RValue versions of the operations declared above. -+ StatusOr(Status&& status); -+ StatusOr& operator=(Status&& status); -+ -+ // Returns this->status().ok() -+ bool ok() const { return this->status_.ok(); } -+ -+ // Returns a reference to our status. If this contains a T, then -+ // returns OkStatus(). -+ const Status& status() const&; -+ Status status() &&; -+ -+ // Returns a reference to our current value, or CHECK-fails if !this->ok(). -+ // -+ // DEPRECATED: Prefer accessing the value using `operator*` or `operator->` -+ // after testing that the StatusOr is OK. If program termination is desired in -+ // the case of an error status, consider `CHECK_OK(status_or);`. -+ // Note: for value types that are cheap to copy, prefer simple code: -+ // -+ // T value = statusor.value(); -+ // -+ // Otherwise, if the value type is expensive to copy, but can be left -+ // in the StatusOr, simply assign to a reference: -+ // -+ // T& value = statusor.value(); // or `const T&` -+ // -+ // Otherwise, if the value type supports an efficient move, it can be -+ // used as follows: -+ // -+ // T value = std::move(statusor).value(); -+ // -+ // The std::move on statusor instead of on the whole expression enables -+ // warnings about possible uses of the statusor object after the move. -+ // C++ style guide waiver for ref-qualified overloads granted in cl/143176389 -+ // See go/ref-qualifiers for more details on such overloads. -+ const T& value() const&; -+ T& value() &; -+ const T&& value() const&&; -+ T&& value() &&; -+ -+ // Returns a reference to the current value. -+ // -+ // REQUIRES: this->ok() == true, otherwise the behavior is undefined. -+ // -+ // Use this->ok() or `operator bool()` to verify that there is a current -+ // value. Alternatively, see value() for a similar API that guarantees -+ // CHECK-failing if there is no current value. -+ const T& operator*() const&; -+ T& operator*() &; -+ const T&& operator*() const&&; -+ T&& operator*() &&; -+ -+ // Returns a pointer to the current value. -+ // -+ // REQUIRES: this->ok() == true, otherwise the behavior is undefined. -+ // -+ // Use this->ok() or `operator bool()` to verify that there is a current -+ // value. -+ const T* operator->() const; -+ T* operator->(); -+ -+ // Ignores any errors. This method does nothing except potentially suppress -+ // complaints from any tools that are checking that errors are not dropped on -+ // the floor. -+ void IgnoreError() const; -+}; -+ -+//////////////////////////////////////////////////////////////////////////////// -+// Implementation details for StatusOr -+ -+template -+StatusOr::StatusOr() : Base(Status(absl::StatusCode::kUnknown, "")) {} -+ -+template -+StatusOr::StatusOr(const T& value) : Base(value) {} -+ -+template -+StatusOr::StatusOr(const Status& status) : Base(status) {} -+ -+template -+StatusOr& StatusOr::operator=(const Status& status) { -+ this->Assign(status); -+ return *this; -+} -+ -+template -+StatusOr::StatusOr(T&& value) : Base(std::move(value)) {} -+ -+template -+template -+StatusOr::StatusOr(absl::in_place_t, Args&&... args) -+ : Base(absl::in_place, std::forward(args)...) {} -+ -+template -+StatusOr::StatusOr(Status&& status) : Base(std::move(status)) {} -+ -+template -+StatusOr& StatusOr::operator=(Status&& status) { -+ this->Assign(std::move(status)); -+ return *this; -+} -+ -+template -+template ::value>::type*> -+inline StatusOr::StatusOr(const StatusOr& other) -+ : Base(static_cast::Base&>(other)) {} -+ -+template -+template ::value>::type*> -+inline StatusOr& StatusOr::operator=(const StatusOr& other) { -+ if (other.ok()) -+ this->Assign(other.value()); -+ else -+ this->Assign(other.status()); -+ return *this; -+} -+ -+template -+template ::value>::type*> -+inline StatusOr::StatusOr(StatusOr&& other) -+ : Base(static_cast::Base&&>(other)) {} -+ -+template -+template ::value>::type*> -+inline StatusOr& StatusOr::operator=(StatusOr&& other) { -+ if (other.ok()) { -+ this->Assign(std::move(other).value()); -+ } else { -+ this->Assign(std::move(other).status()); -+ } -+ return *this; -+} -+ -+template -+const Status& StatusOr::status() const& { -+ return this->status_; -+} -+template -+Status StatusOr::status() && { -+ // Note that we copy instead of moving the status here so that -+ // ~StatusOrData() can call ok() without invoking UB. -+ return ok() ? OkStatus() : this->status_; -+} -+ -+template -+const T& StatusOr::value() const& { -+ this->EnsureOk(); -+ return this->data_; -+} -+ -+template -+T& StatusOr::value() & { -+ this->EnsureOk(); -+ return this->data_; -+} -+ -+template -+const T&& StatusOr::value() const&& { -+ this->EnsureOk(); -+ return std::move(this->data_); -+} -+ -+template -+T&& StatusOr::value() && { -+ this->EnsureOk(); -+ return std::move(this->data_); -+} -+ -+template -+const T* StatusOr::operator->() const { -+ this->EnsureOk(); -+ return &this->data_; -+} -+ -+template -+T* StatusOr::operator->() { -+ this->EnsureOk(); -+ return &this->data_; -+} -+ -+template -+const T& StatusOr::operator*() const& { -+ this->EnsureOk(); -+ return this->data_; -+} -+ -+template -+T& StatusOr::operator*() & { -+ this->EnsureOk(); -+ return this->data_; -+} -+ -+template -+const T&& StatusOr::operator*() const&& { -+ this->EnsureOk(); -+ return std::move(this->data_); -+} -+ -+template -+T&& StatusOr::operator*() && { -+ this->EnsureOk(); -+ return std::move(this->data_); -+} -+ -+template -+void StatusOr::IgnoreError() const { -+ // no-op -+} - - #define TF_ASSERT_OK_AND_ASSIGN(lhs, rexpr) \ - TF_ASSERT_OK_AND_ASSIGN_IMPL( \ -diff --git a/third_party/tsl/tsl/platform/statusor_internals.h b/third_party/tsl/tsl/platform/statusor_internals.h -new file mode 100644 -index 000000000..a57dd2847 ---- /dev/null -+++ b/third_party/tsl/tsl/platform/statusor_internals.h -@@ -0,0 +1,253 @@ -+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. -+ -+Licensed under the Apache License, Version 2.0 (the "License"); -+you may not use this file except in compliance with the License. -+You may obtain a copy of the License at -+ -+ http://www.apache.org/licenses/LICENSE-2.0 -+ -+Unless required by applicable law or agreed to in writing, software -+distributed under the License is distributed on an "AS IS" BASIS, -+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+See the License for the specific language governing permissions and -+limitations under the License. -+==============================================================================*/ -+ -+#ifndef TSL_PLATFORM_STATUSOR_INTERNALS_H_ -+#define TSL_PLATFORM_STATUSOR_INTERNALS_H_ -+ -+#include "tsl/platform/macros.h" -+#include "tsl/platform/status.h" -+ -+namespace tsl { -+namespace internal_statusor { -+ -+class Helper { -+ public: -+ // Move type-agnostic error handling to the .cc. -+ static void HandleInvalidStatusCtorArg(Status*); -+ TF_ATTRIBUTE_NORETURN static void Crash(const Status& status); -+}; -+ -+// Construct an instance of T in `p` through placement new, passing Args... to -+// the constructor. -+// This abstraction is here mostly for the gcc performance fix. -+template -+void PlacementNew(void* p, Args&&... args) { -+#if defined(__GNUC__) && !defined(__clang__) -+ // Teach gcc that 'p' cannot be null, fixing code size issues. -+ if (p == nullptr) __builtin_unreachable(); -+#endif -+ new (p) T(std::forward(args)...); -+} -+ -+// Helper base class to hold the data and all operations. -+// We move all this to a base class to allow mixing with the appropriate -+// TraitsBase specialization. -+template -+class StatusOrData { -+ template -+ friend class StatusOrData; -+ -+ public: -+ StatusOrData() = delete; -+ -+ StatusOrData(const StatusOrData& other) { -+ if (other.ok()) { -+ MakeValue(other.data_); -+ MakeStatus(); -+ } else { -+ MakeStatus(other.status_); -+ } -+ } -+ -+ StatusOrData(StatusOrData&& other) noexcept { -+ if (other.ok()) { -+ MakeValue(std::move(other.data_)); -+ MakeStatus(); -+ } else { -+ MakeStatus(other.status_); -+ } -+ } -+ -+ template -+ StatusOrData(const StatusOrData& other) { -+ if (other.ok()) { -+ MakeValue(other.data_); -+ MakeStatus(); -+ } else { -+ MakeStatus(other.status_); -+ } -+ } -+ -+ template -+ StatusOrData(StatusOrData&& other) { -+ if (other.ok()) { -+ MakeValue(std::move(other.data_)); -+ MakeStatus(); -+ } else { -+ MakeStatus(other.status_); -+ } -+ } -+ -+ explicit StatusOrData(const T& value) : data_(value) { MakeStatus(); } -+ explicit StatusOrData(T&& value) : data_(std::move(value)) { MakeStatus(); } -+ -+ template -+ explicit StatusOrData(absl::in_place_t, Args&&... args) -+ : data_(std::forward(args)...) { -+ MakeStatus(); -+ } -+ -+ explicit StatusOrData(const Status& status) : status_(status) { -+ EnsureNotOk(); -+ } -+ explicit StatusOrData(Status&& status) : status_(std::move(status)) { -+ EnsureNotOk(); -+ } -+ -+ StatusOrData& operator=(const StatusOrData& other) { -+ if (this == &other) return *this; -+ if (other.ok()) -+ Assign(other.data_); -+ else -+ Assign(other.status_); -+ return *this; -+ } -+ -+ StatusOrData& operator=(StatusOrData&& other) { -+ if (this == &other) return *this; -+ if (other.ok()) -+ Assign(std::move(other.data_)); -+ else -+ Assign(std::move(other.status_)); -+ return *this; -+ } -+ -+ ~StatusOrData() { -+ if (ok()) { -+ status_.~Status(); -+ data_.~T(); -+ } else { -+ status_.~Status(); -+ } -+ } -+ -+ void Assign(const T& value) { -+ if (ok()) { -+ data_.~T(); -+ MakeValue(value); -+ } else { -+ MakeValue(value); -+ status_ = OkStatus(); -+ } -+ } -+ -+ void Assign(T&& value) { -+ if (ok()) { -+ data_.~T(); -+ MakeValue(std::move(value)); -+ } else { -+ MakeValue(std::move(value)); -+ status_ = OkStatus(); -+ } -+ } -+ -+ void Assign(const Status& status) { -+ Clear(); -+ status_ = status; -+ EnsureNotOk(); -+ } -+ -+ void Assign(Status&& status) { -+ Clear(); -+ // Note that we copy instead of moving the status here so that -+ // status.~StatusOrData() can call ok() without invoking UB. -+ status_ = status; -+ EnsureNotOk(); -+ } -+ -+ bool ok() const { return status_.ok(); } -+ -+ protected: -+ // status_ will always be active after the constructor. -+ // We make it a union to be able to initialize exactly how we need without -+ // waste. -+ // Eg. in the copy constructor we use the default constructor of Status in -+ // the ok() path to avoid an extra Ref call. -+ union { -+ Status status_; -+ }; -+ -+ // data_ is active iff status_.ok()==true -+ struct Dummy {}; -+ union { -+ // When T is const, we need some non-const object we can cast to void* for -+ // the placement new. dummy_ is that object. -+ Dummy dummy_; -+ T data_; -+ }; -+ -+ void Clear() { -+ if (ok()) data_.~T(); -+ } -+ -+ void EnsureOk() const { -+ if (!ok()) Helper::Crash(status_); -+ } -+ -+ void EnsureNotOk() { -+ if (ok()) Helper::HandleInvalidStatusCtorArg(&status_); -+ } -+ -+ // Construct the value (ie. data_) through placement new with the passed -+ // argument. -+ template -+ void MakeValue(Arg&& arg) { -+ internal_statusor::PlacementNew(&dummy_, std::forward(arg)); -+ } -+ -+ // Construct the status (ie. status_) through placement new with the passed -+ // argument. -+ template -+ void MakeStatus(Args&&... args) { -+ internal_statusor::PlacementNew(&status_, -+ std::forward(args)...); -+ } -+}; -+ -+// Helper base class to allow implicitly deleted constructors and assignment -+// operations in StatusOr. -+// TraitsBase will explicitly delete what it can't support and StatusOr will -+// inherit that behavior implicitly. -+template -+struct TraitsBase { -+ TraitsBase() = default; -+ TraitsBase(const TraitsBase&) = default; -+ TraitsBase(TraitsBase&&) = default; -+ TraitsBase& operator=(const TraitsBase&) = default; -+ TraitsBase& operator=(TraitsBase&&) = default; -+}; -+ -+template <> -+struct TraitsBase { -+ TraitsBase() = default; -+ TraitsBase(const TraitsBase&) = delete; -+ TraitsBase(TraitsBase&&) = default; -+ TraitsBase& operator=(const TraitsBase&) = delete; -+ TraitsBase& operator=(TraitsBase&&) = default; -+}; -+ -+template <> -+struct TraitsBase { -+ TraitsBase() = default; -+ TraitsBase(const TraitsBase&) = delete; -+ TraitsBase(TraitsBase&&) = delete; -+ TraitsBase& operator=(const TraitsBase&) = delete; -+ TraitsBase& operator=(TraitsBase&&) = delete; -+}; -+ -+} // namespace internal_statusor -+} // namespace tsl -+ -+#endif // TSL_PLATFORM_STATUSOR_INTERNALS_H_ -\ No newline at end of file \ No newline at end of file