LCOV - code coverage report
Current view: top level - /usr/lib/llvm-19/include/llvm/Support - ErrorOr.h (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 0.0 % 15 0
Test Date: 2026-07-03 19:57:34 Functions: 0.0 % 6 0
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 0.0 % 8 0

             Branch data     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                 :           0 :   ~ErrorOr() {
     140         [ #  # ]:           0 :     if (!HasError)
     141                 :           0 :       getStorage()->~storage_type();
     142                 :           0 :   }
     143                 :             : 
     144                 :             :   /// Return false if there is an error.
     145                 :             :   explicit operator bool() const {
     146                 :             :     return !HasError;
     147                 :             :   }
     148                 :             : 
     149                 :           0 :   reference get() { return *getStorage(); }
     150                 :             :   const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
     151                 :             : 
     152                 :           0 :   std::error_code getError() const {
     153         [ #  # ]:           0 :     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                 :           0 :   storage_type *getStorage() {
     236         [ #  # ]:           0 :     assert(!HasError && "Cannot get value when an error exists!");
     237                 :           0 :     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