diff --git a/common/error.h b/common/error.h index 8b29e66ae41f..ec18eb9d1a2e 100644 --- a/common/error.h +++ b/common/error.h @@ -5,7 +5,9 @@ #ifndef CARBON_COMMON_ERROR_H_ #define CARBON_COMMON_ERROR_H_ +#include #include +#include #include #include "common/check.h" @@ -76,18 +78,29 @@ class [[nodiscard]] Error : public Printable { template class [[nodiscard]] ErrorOr { public: + using ValueT = std::remove_reference_t; + // Constructs with an error; the error must not be Error::Success(). // Implicit for easy construction on returns. // NOLINTNEXTLINE(google-explicit-constructor) ErrorOr(Error err) : val_(std::move(err)) {} + // Constructs with a reference. + // Implicit for easy construction on returns. + // NOLINTNEXTLINE(google-explicit-constructor) + ErrorOr(T ref) + requires std::is_reference_v + : val_(std::ref(ref)) {} + // Constructs with a value. // Implicit for easy construction on returns. // NOLINTNEXTLINE(google-explicit-constructor) - ErrorOr(T val) : val_(std::move(val)) {} + ErrorOr(T val) + requires(!std::is_reference_v) + : val_(std::move(val)) {} // Returns true for success. - auto ok() const -> bool { return std::holds_alternative(val_); } + auto ok() const -> bool { return std::holds_alternative(val_); } // Returns the contained error. // REQUIRES: `ok()` is false. @@ -102,35 +115,32 @@ class [[nodiscard]] ErrorOr { // Returns the contained value. // REQUIRES: `ok()` is true. - auto operator*() -> T& { + auto operator*() -> ValueT& { CARBON_CHECK(ok()); - return std::get(val_); + return std::get(val_); } // Returns the contained value. // REQUIRES: `ok()` is true. - auto operator*() const -> const T& { + auto operator*() const -> const ValueT& { CARBON_CHECK(ok()); - return std::get(val_); + return std::get(val_); } // Returns the contained value. // REQUIRES: `ok()` is true. - auto operator->() -> T* { - CARBON_CHECK(ok()); - return &std::get(val_); - } + auto operator->() -> ValueT* { return &**this; } // Returns the contained value. // REQUIRES: `ok()` is true. - auto operator->() const -> const T* { - CARBON_CHECK(ok()); - return &std::get(val_); - } + auto operator->() const -> const ValueT* { return &**this; } private: + using StoredT = std::conditional_t, + std::reference_wrapper, T>; + // Either an error message or a value. - std::variant val_; + std::variant val_; }; // A helper class for accumulating error message and converting to diff --git a/common/error_test.cpp b/common/error_test.cpp index ebe56ae194f1..1e5dac824fae 100644 --- a/common/error_test.cpp +++ b/common/error_test.cpp @@ -50,6 +50,12 @@ TEST(ErrorTest, ErrorOrArrowOp) { EXPECT_EQ(err->val, 1); } +TEST(ErrorTest, ErrorOrReference) { + Val val = {1}; + ErrorOr maybe_val(val); + EXPECT_EQ(maybe_val->val, 1); +} + auto IndirectErrorOrSuccessTest() -> ErrorOr { return Success(); } TEST(ErrorTest, IndirectErrorOrSuccess) {