LCOV - code coverage report
Current view: top level - /usr/lib/llvm-19/include/llvm/Support - ErrorOr.h (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 66.7 % 15 10
Test Date: 2026-02-27 05:14:50 Functions: 66.7 % 6 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : //===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===//
       2              : //
       3              : // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
       4              : // See https://llvm.org/LICENSE.txt for license information.
       5              : // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
       6              : //
       7              : //===----------------------------------------------------------------------===//
       8              : ///
       9              : /// \file
      10              : ///
      11              : /// Provides ErrorOr<T> smart pointer.
      12              : ///
      13              : //===----------------------------------------------------------------------===//
      14              : 
      15              : #ifndef LLVM_SUPPORT_ERROROR_H
      16              : #define LLVM_SUPPORT_ERROROR_H
      17              : 
      18              : #include "llvm/Support/AlignOf.h"
      19              : #include <cassert>
      20              : #include <system_error>
      21              : #include <type_traits>
      22              : #include <utility>
      23              : 
      24              : namespace llvm {
      25              : 
      26              : /// Represents either an error or a value T.
      27              : ///
      28              : /// ErrorOr<T> is a pointer-like class that represents the result of an
      29              : /// operation. The result is either an error, or a value of type T. This is
      30              : /// designed to emulate the usage of returning a pointer where nullptr indicates
      31              : /// failure. However instead of just knowing that the operation failed, we also
      32              : /// have an error_code and optional user data that describes why it failed.
      33              : ///
      34              : /// It is used like the following.
      35              : /// \code
      36              : ///   ErrorOr<Buffer> getBuffer();
      37              : ///
      38              : ///   auto buffer = getBuffer();
      39              : ///   if (error_code ec = buffer.getError())
      40              : ///     return ec;
      41              : ///   buffer->write("adena");
      42              : /// \endcode
      43              : ///
      44              : ///
      45              : /// Implicit conversion to bool returns true if there is a usable value. The
      46              : /// unary * and -> operators provide pointer like access to the value. Accessing
      47              : /// the value when there is an error has undefined behavior.
      48              : ///
      49              : /// When T is a reference type the behavior is slightly different. The reference
      50              : /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
      51              : /// there is special handling to make operator -> work as if T was not a
      52              : /// reference.
      53              : ///
      54              : /// T cannot be a rvalue reference.
      55              : template<class T>
      56              : class ErrorOr {
      57              :   template <class OtherT> friend class ErrorOr;
      58              : 
      59              :   static constexpr bool isRef = std::is_reference_v<T>;
      60              : 
      61              :   using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
      62              : 
      63              : public:
      64              :   using storage_type = std::conditional_t<isRef, wrap, T>;
      65              : 
      66              : private:
      67              :   using reference = std::remove_reference_t<T> &;
      68              :   using const_reference = const std::remove_reference_t<T> &;
      69              :   using pointer = std::remove_reference_t<T> *;
      70              :   using const_pointer = const std::remove_reference_t<T> *;
      71              : 
      72              : public:
      73              :   template <class E>
      74              :   ErrorOr(E ErrorCode,
      75              :           std::enable_if_t<std::is_error_code_enum<E>::value ||
      76              :                                std::is_error_condition_enum<E>::value,
      77              :                            void *> = nullptr)
      78              :       : HasError(true) {
      79              :     new (getErrorStorage()) std::error_code(make_error_code(ErrorCode));
      80              :   }
      81              : 
      82              :   ErrorOr(std::error_code EC) : HasError(true) {
      83              :     new (getErrorStorage()) std::error_code(EC);
      84              :   }
      85              : 
      86              :   template <class OtherT>
      87              :   ErrorOr(OtherT &&Val,
      88              :           std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr)
      89              :       : HasError(false) {
      90              :     new (getStorage()) storage_type(std::forward<OtherT>(Val));
      91              :   }
      92              : 
      93              :   ErrorOr(const ErrorOr &Other) {
      94              :     copyConstruct(Other);
      95              :   }
      96              : 
      97              :   template <class OtherT>
      98              :   ErrorOr(const ErrorOr<OtherT> &Other,
      99              :           std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) {
     100              :     copyConstruct(Other);
     101              :   }
     102              : 
     103              :   template <class OtherT>
     104              :   explicit ErrorOr(
     105              :       const ErrorOr<OtherT> &Other,
     106              :       std::enable_if_t<!std::is_convertible_v<OtherT, const T &>> * = nullptr) {
     107              :     copyConstruct(Other);
     108              :   }
     109              : 
     110              :   ErrorOr(ErrorOr &&Other) {
     111              :     moveConstruct(std::move(Other));
     112              :   }
     113              : 
     114              :   template <class OtherT>
     115              :   ErrorOr(ErrorOr<OtherT> &&Other,
     116              :           std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) {
     117              :     moveConstruct(std::move(Other));
     118              :   }
     119              : 
     120              :   // This might eventually need SFINAE but it's more complex than is_convertible
     121              :   // & I'm too lazy to write it right now.
     122              :   template <class OtherT>
     123              :   explicit ErrorOr(
     124              :       ErrorOr<OtherT> &&Other,
     125              :       std::enable_if_t<!std::is_convertible_v<OtherT, T>> * = nullptr) {
     126              :     moveConstruct(std::move(Other));
     127              :   }
     128              : 
     129              :   ErrorOr &operator=(const ErrorOr &Other) {
     130              :     copyAssign(Other);
     131              :     return *this;
     132              :   }
     133              : 
     134              :   ErrorOr &operator=(ErrorOr &&Other) {
     135              :     moveAssign(std::move(Other));
     136              :     return *this;
     137              :   }
     138              : 
     139           45 :   ~ErrorOr() {
     140           45 :     if (!HasError)
     141           45 :       getStorage()->~storage_type();
     142           45 :   }
     143              : 
     144              :   /// Return false if there is an error.
     145              :   explicit operator bool() const {
     146              :     return !HasError;
     147              :   }
     148              : 
     149           45 :   reference get() { return *getStorage(); }
     150              :   const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
     151              : 
     152           45 :   std::error_code getError() const {
     153           45 :     return HasError ? *getErrorStorage() : std::error_code();
     154              :   }
     155              : 
     156              :   pointer operator ->() {
     157              :     return toPointer(getStorage());
     158              :   }
     159              : 
     160              :   const_pointer operator->() const { return toPointer(getStorage()); }
     161              : 
     162              :   reference operator *() {
     163              :     return *getStorage();
     164              :   }
     165              : 
     166              :   const_reference operator*() const { return *getStorage(); }
     167              : 
     168              : private:
     169              :   template <class OtherT>
     170              :   void copyConstruct(const ErrorOr<OtherT> &Other) {
     171              :     if (!Other.HasError) {
     172              :       // Get the other value.
     173              :       HasError = false;
     174              :       new (getStorage()) storage_type(*Other.getStorage());
     175              :     } else {
     176              :       // Get other's error.
     177              :       HasError = true;
     178              :       new (getErrorStorage()) std::error_code(Other.getError());
     179              :     }
     180              :   }
     181              : 
     182              :   template <class T1>
     183              :   static bool compareThisIfSameType(const T1 &a, const T1 &b) {
     184              :     return &a == &b;
     185              :   }
     186              : 
     187              :   template <class T1, class T2>
     188              :   static bool compareThisIfSameType(const T1 &a, const T2 &b) {
     189              :     return false;
     190              :   }
     191              : 
     192              :   template <class OtherT>
     193              :   void copyAssign(const ErrorOr<OtherT> &Other) {
     194              :     if (compareThisIfSameType(*this, Other))
     195              :       return;
     196              : 
     197              :     this->~ErrorOr();
     198              :     new (this) ErrorOr(Other);
     199              :   }
     200              : 
     201              :   template <class OtherT>
     202              :   void moveConstruct(ErrorOr<OtherT> &&Other) {
     203              :     if (!Other.HasError) {
     204              :       // Get the other value.
     205              :       HasError = false;
     206              :       new (getStorage()) storage_type(std::move(*Other.getStorage()));
     207              :     } else {
     208              :       // Get other's error.
     209              :       HasError = true;
     210              :       new (getErrorStorage()) std::error_code(Other.getError());
     211              :     }
     212              :   }
     213              : 
     214              :   template <class OtherT>
     215              :   void moveAssign(ErrorOr<OtherT> &&Other) {
     216              :     if (compareThisIfSameType(*this, Other))
     217              :       return;
     218              : 
     219              :     this->~ErrorOr();
     220              :     new (this) ErrorOr(std::move(Other));
     221              :   }
     222              : 
     223              :   pointer toPointer(pointer Val) {
     224              :     return Val;
     225              :   }
     226              : 
     227              :   const_pointer toPointer(const_pointer Val) const { return Val; }
     228              : 
     229              :   pointer toPointer(wrap *Val) {
     230              :     return &Val->get();
     231              :   }
     232              : 
     233              :   const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
     234              : 
     235           90 :   storage_type *getStorage() {
     236           90 :     assert(!HasError && "Cannot get value when an error exists!");
     237           90 :     return reinterpret_cast<storage_type *>(&TStorage);
     238              :   }
     239              : 
     240              :   const storage_type *getStorage() const {
     241              :     assert(!HasError && "Cannot get value when an error exists!");
     242              :     return reinterpret_cast<const storage_type *>(&TStorage);
     243              :   }
     244              : 
     245            0 :   std::error_code *getErrorStorage() {
     246            0 :     assert(HasError && "Cannot get error when a value exists!");
     247            0 :     return reinterpret_cast<std::error_code *>(&ErrorStorage);
     248              :   }
     249              : 
     250            0 :   const std::error_code *getErrorStorage() const {
     251            0 :     return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
     252              :   }
     253              : 
     254              :   union {
     255              :     AlignedCharArrayUnion<storage_type> TStorage;
     256              :     AlignedCharArrayUnion<std::error_code> ErrorStorage;
     257              :   };
     258              :   bool HasError : 1;
     259              : };
     260              : 
     261              : template <class T, class E>
     262              : std::enable_if_t<std::is_error_code_enum<E>::value ||
     263              :                      std::is_error_condition_enum<E>::value,
     264              :                  bool>
     265              : operator==(const ErrorOr<T> &Err, E Code) {
     266              :   return Err.getError() == Code;
     267              : }
     268              : 
     269              : } // end namespace llvm
     270              : 
     271              : #endif // LLVM_SUPPORT_ERROROR_H
        

Generated by: LCOV version 2.0-1