1 //===- llvm/Support/ErrorOr.h - Error Smart Pointer -----------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// 12 /// Provides ErrorOr<T> smart pointer. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_SUPPORT_ERROR_OR_H 17 #define LLVM_SUPPORT_ERROR_OR_H 18 19 #include "llvm/ADT/PointerIntPair.h" 20 #include "llvm/Support/AlignOf.h" 21 #include "llvm/Support/system_error.h" 22 #include "llvm/Support/type_traits.h" 23 24 #include <cassert> 25 #if LLVM_HAS_CXX11_TYPETRAITS 26 #include <type_traits> 27 #endif 28 29 namespace llvm { 30 struct ErrorHolderBase { 31 error_code Error; 32 uint16_t RefCount; 33 bool HasUserData; 34 35 ErrorHolderBase() : RefCount(1) {} 36 37 void aquire() { 38 ++RefCount; 39 } 40 41 void release() { 42 if (--RefCount == 0) 43 delete this; 44 } 45 46 protected: 47 virtual ~ErrorHolderBase() {} 48 }; 49 50 template<class T> 51 struct ErrorHolder : ErrorHolderBase { 52 #if LLVM_HAS_RVALUE_REFERENCES 53 ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {} 54 #else 55 ErrorHolder(T &UD) : UserData(UD) {} 56 #endif 57 T UserData; 58 }; 59 60 template<class Tp> struct ErrorOrUserDataTraits : llvm::false_type {}; 61 62 #if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES 63 template<class T, class V> 64 typename std::enable_if< std::is_constructible<T, V>::value 65 , typename std::remove_reference<V>::type>::type && 66 moveIfMoveConstructible(V &Val) { 67 return std::move(Val); 68 } 69 70 template<class T, class V> 71 typename std::enable_if< !std::is_constructible<T, V>::value 72 , typename std::remove_reference<V>::type>::type & 73 moveIfMoveConstructible(V &Val) { 74 return Val; 75 } 76 #else 77 template<class T, class V> 78 V &moveIfMoveConstructible(V &Val) { 79 return Val; 80 } 81 #endif 82 83 /// \brief Stores a reference that can be changed. 84 template <typename T> 85 class ReferenceStorage { 86 T *Storage; 87 88 public: 89 ReferenceStorage(T &Ref) : Storage(&Ref) {} 90 91 operator T &() const { return *Storage; } 92 T &get() const { return *Storage; } 93 }; 94 95 /// \brief Represents either an error or a value T. 96 /// 97 /// ErrorOr<T> is a pointer-like class that represents the result of an 98 /// operation. The result is either an error, or a value of type T. This is 99 /// designed to emulate the usage of returning a pointer where nullptr indicates 100 /// failure. However instead of just knowing that the operation failed, we also 101 /// have an error_code and optional user data that describes why it failed. 102 /// 103 /// It is used like the following. 104 /// \code 105 /// ErrorOr<Buffer> getBuffer(); 106 /// void handleError(error_code ec); 107 /// 108 /// auto buffer = getBuffer(); 109 /// if (!buffer) 110 /// handleError(buffer); 111 /// buffer->write("adena"); 112 /// \endcode 113 /// 114 /// ErrorOr<T> also supports user defined data for specific error_codes. To use 115 /// this feature you must first add a template specialization of 116 /// ErrorOrUserDataTraits derived from std::true_type for your type in the lld 117 /// namespace. This specialization must have a static error_code error() 118 /// function that returns the error_code this data is used with. 119 /// 120 /// getError<UserData>() may be called to get either the stored user data, or 121 /// a default constructed UserData if none was stored. 122 /// 123 /// Example: 124 /// \code 125 /// struct InvalidArgError { 126 /// InvalidArgError() {} 127 /// InvalidArgError(std::string S) : ArgName(S) {} 128 /// std::string ArgName; 129 /// }; 130 /// 131 /// namespace llvm { 132 /// template<> 133 /// struct ErrorOrUserDataTraits<InvalidArgError> : std::true_type { 134 /// static error_code error() { 135 /// return make_error_code(errc::invalid_argument); 136 /// } 137 /// }; 138 /// } // end namespace llvm 139 /// 140 /// using namespace llvm; 141 /// 142 /// ErrorOr<int> foo() { 143 /// return InvalidArgError("adena"); 144 /// } 145 /// 146 /// int main() { 147 /// auto a = foo(); 148 /// if (!a && error_code(a) == errc::invalid_argument) 149 /// llvm::errs() << a.getError<InvalidArgError>().ArgName << "\n"; 150 /// } 151 /// \endcode 152 /// 153 /// An implicit conversion to bool provides a way to check if there was an 154 /// error. The unary * and -> operators provide pointer like access to the 155 /// value. Accessing the value when there is an error has undefined behavior. 156 /// 157 /// When T is a reference type the behaivor is slightly different. The reference 158 /// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and 159 /// there is special handling to make operator -> work as if T was not a 160 /// reference. 161 /// 162 /// T cannot be a rvalue reference. 163 template<class T> 164 class ErrorOr { 165 template <class OtherT> friend class ErrorOr; 166 static const bool isRef = is_reference<T>::value; 167 typedef ReferenceStorage<typename remove_reference<T>::type> wrap; 168 169 public: 170 typedef typename 171 conditional< isRef 172 , wrap 173 , T 174 >::type storage_type; 175 176 private: 177 typedef typename remove_reference<T>::type &reference; 178 typedef typename remove_reference<T>::type *pointer; 179 180 public: 181 ErrorOr() : IsValid(false) {} 182 183 template <class E> 184 ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value || 185 is_error_condition_enum<E>::value, 186 void *>::type = 0) 187 : HasError(true), IsValid(true) { 188 Error = new ErrorHolderBase; 189 Error->Error = make_error_code(ErrorCode); 190 Error->HasUserData = false; 191 } 192 193 ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) { 194 Error = new ErrorHolderBase; 195 Error->Error = EC; 196 Error->HasUserData = false; 197 } 198 199 template<class UserDataT> 200 ErrorOr(UserDataT UD, typename 201 enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0) 202 : HasError(true), IsValid(true) { 203 Error = new ErrorHolder<UserDataT>(llvm_move(UD)); 204 Error->Error = ErrorOrUserDataTraits<UserDataT>::error(); 205 Error->HasUserData = true; 206 } 207 208 ErrorOr(T Val) : HasError(false), IsValid(true) { 209 new (get()) storage_type(moveIfMoveConstructible<storage_type>(Val)); 210 } 211 212 ErrorOr(const ErrorOr &Other) : IsValid(false) { 213 copyConstruct(Other); 214 } 215 216 template <class OtherT> 217 ErrorOr(const ErrorOr<OtherT> &Other) : IsValid(false) { 218 copyConstruct(Other); 219 } 220 221 ErrorOr &operator =(const ErrorOr &Other) { 222 copyAssign(Other); 223 return *this; 224 } 225 226 template <class OtherT> 227 ErrorOr &operator =(const ErrorOr<OtherT> &Other) { 228 copyAssign(Other); 229 return *this; 230 } 231 232 #if LLVM_HAS_RVALUE_REFERENCES 233 ErrorOr(ErrorOr &&Other) : IsValid(false) { 234 moveConstruct(std::move(Other)); 235 } 236 237 template <class OtherT> 238 ErrorOr(ErrorOr<OtherT> &&Other) : IsValid(false) { 239 moveConstruct(std::move(Other)); 240 } 241 242 ErrorOr &operator =(ErrorOr &&Other) { 243 moveAssign(std::move(Other)); 244 return *this; 245 } 246 247 template <class OtherT> 248 ErrorOr &operator =(ErrorOr<OtherT> &&Other) { 249 moveAssign(std::move(Other)); 250 return *this; 251 } 252 #endif 253 254 ~ErrorOr() { 255 if (!IsValid) 256 return; 257 if (HasError) 258 Error->release(); 259 else 260 get()->~storage_type(); 261 } 262 263 template<class ET> 264 ET getError() const { 265 assert(IsValid && "Cannot get the error of a default constructed ErrorOr!"); 266 assert(HasError && "Cannot get an error if none exists!"); 267 assert(ErrorOrUserDataTraits<ET>::error() == Error->Error && 268 "Incorrect user error data type for error!"); 269 if (!Error->HasUserData) 270 return ET(); 271 return reinterpret_cast<const ErrorHolder<ET>*>(Error)->UserData; 272 } 273 274 typedef void (*unspecified_bool_type)(); 275 static void unspecified_bool_true() {} 276 277 /// \brief Return false if there is an error. 278 operator unspecified_bool_type() const { 279 assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); 280 return HasError ? 0 : unspecified_bool_true; 281 } 282 283 operator llvm::error_code() const { 284 assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); 285 return HasError ? Error->Error : llvm::error_code::success(); 286 } 287 288 pointer operator ->() { 289 return toPointer(get()); 290 } 291 292 reference operator *() { 293 return *get(); 294 } 295 296 private: 297 template <class OtherT> 298 void copyConstruct(const ErrorOr<OtherT> &Other) { 299 // Construct an invalid ErrorOr if other is invalid. 300 if (!Other.IsValid) 301 return; 302 IsValid = true; 303 if (!Other.HasError) { 304 // Get the other value. 305 HasError = false; 306 new (get()) storage_type(*Other.get()); 307 } else { 308 // Get other's error. 309 Error = Other.Error; 310 HasError = true; 311 Error->aquire(); 312 } 313 } 314 315 template <class T1> 316 static bool compareThisIfSameType(const T1 &a, const T1 &b) { 317 return &a == &b; 318 } 319 320 template <class T1, class T2> 321 static bool compareThisIfSameType(const T1 &a, const T2 &b) { 322 return false; 323 } 324 325 template <class OtherT> 326 void copyAssign(const ErrorOr<OtherT> &Other) { 327 if (compareThisIfSameType(*this, Other)) 328 return; 329 330 this->~ErrorOr(); 331 new (this) ErrorOr(Other); 332 } 333 334 #if LLVM_HAS_RVALUE_REFERENCES 335 template <class OtherT> 336 void moveConstruct(ErrorOr<OtherT> &&Other) { 337 // Construct an invalid ErrorOr if other is invalid. 338 if (!Other.IsValid) 339 return; 340 IsValid = true; 341 if (!Other.HasError) { 342 // Get the other value. 343 HasError = false; 344 new (get()) storage_type(std::move(*Other.get())); 345 // Tell other not to do any destruction. 346 Other.IsValid = false; 347 } else { 348 // Get other's error. 349 Error = Other.Error; 350 HasError = true; 351 // Tell other not to do any destruction. 352 Other.IsValid = false; 353 } 354 } 355 356 template <class OtherT> 357 void moveAssign(ErrorOr<OtherT> &&Other) { 358 if (compareThisIfSameType(*this, Other)) 359 return; 360 361 this->~ErrorOr(); 362 new (this) ErrorOr(std::move(Other)); 363 } 364 #endif 365 366 pointer toPointer(pointer Val) { 367 return Val; 368 } 369 370 pointer toPointer(wrap *Val) { 371 return &Val->get(); 372 } 373 374 storage_type *get() { 375 assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); 376 assert(!HasError && "Cannot get value when an error exists!"); 377 return reinterpret_cast<storage_type*>(TStorage.buffer); 378 } 379 380 const storage_type *get() const { 381 assert(IsValid && "Can't do anything on a default constructed ErrorOr!"); 382 assert(!HasError && "Cannot get value when an error exists!"); 383 return reinterpret_cast<const storage_type*>(TStorage.buffer); 384 } 385 386 union { 387 AlignedCharArrayUnion<storage_type> TStorage; 388 ErrorHolderBase *Error; 389 }; 390 bool HasError : 1; 391 bool IsValid : 1; 392 }; 393 394 // ErrorOr specialization for void. 395 template <> 396 class ErrorOr<void> { 397 public: 398 ErrorOr() : Error(0, 0) {} 399 400 template <class E> 401 ErrorOr(E ErrorCode, typename enable_if_c<is_error_code_enum<E>::value || 402 is_error_condition_enum<E>::value, 403 void *> ::type = 0) 404 : Error(0, 0) { 405 error_code EC = make_error_code(ErrorCode); 406 if (EC == errc::success) { 407 Error.setInt(1); 408 return; 409 } 410 ErrorHolderBase *EHB = new ErrorHolderBase; 411 EHB->Error = EC; 412 EHB->HasUserData = false; 413 Error.setPointer(EHB); 414 } 415 416 ErrorOr(llvm::error_code EC) : Error(0, 0) { 417 if (EC == errc::success) { 418 Error.setInt(1); 419 return; 420 } 421 ErrorHolderBase *E = new ErrorHolderBase; 422 E->Error = EC; 423 E->HasUserData = false; 424 Error.setPointer(E); 425 } 426 427 template<class UserDataT> 428 ErrorOr(UserDataT UD, typename 429 enable_if_c<ErrorOrUserDataTraits<UserDataT>::value>::type* = 0) 430 : Error(0, 0) { 431 ErrorHolderBase *E = new ErrorHolder<UserDataT>(llvm_move(UD)); 432 E->Error = ErrorOrUserDataTraits<UserDataT>::error(); 433 E->HasUserData = true; 434 Error.setPointer(E); 435 } 436 437 ErrorOr(const ErrorOr &Other) : Error(0, 0) { 438 Error = Other.Error; 439 if (Other.Error.getPointer()->Error) { 440 Error.getPointer()->aquire(); 441 } 442 } 443 444 ErrorOr &operator =(const ErrorOr &Other) { 445 if (this == &Other) 446 return *this; 447 448 this->~ErrorOr(); 449 new (this) ErrorOr(Other); 450 451 return *this; 452 } 453 454 #if LLVM_HAS_RVALUE_REFERENCES 455 ErrorOr(ErrorOr &&Other) : Error(0) { 456 // Get other's error. 457 Error = Other.Error; 458 // Tell other not to do any destruction. 459 Other.Error.setPointer(0); 460 } 461 462 ErrorOr &operator =(ErrorOr &&Other) { 463 if (this == &Other) 464 return *this; 465 466 this->~ErrorOr(); 467 new (this) ErrorOr(std::move(Other)); 468 469 return *this; 470 } 471 #endif 472 473 ~ErrorOr() { 474 if (Error.getPointer()) 475 Error.getPointer()->release(); 476 } 477 478 template<class ET> 479 ET getError() const { 480 assert(ErrorOrUserDataTraits<ET>::error() == *this && 481 "Incorrect user error data type for error!"); 482 if (!Error.getPointer()->HasUserData) 483 return ET(); 484 return reinterpret_cast<const ErrorHolder<ET> *>( 485 Error.getPointer())->UserData; 486 } 487 488 typedef void (*unspecified_bool_type)(); 489 static void unspecified_bool_true() {} 490 491 /// \brief Return false if there is an error. 492 operator unspecified_bool_type() const { 493 return Error.getInt() ? unspecified_bool_true : 0; 494 } 495 496 operator llvm::error_code() const { 497 return Error.getInt() ? make_error_code(errc::success) 498 : Error.getPointer()->Error; 499 } 500 501 private: 502 // If the bit is 1, the error is success. 503 llvm::PointerIntPair<ErrorHolderBase *, 1> Error; 504 }; 505 506 template<class T, class E> 507 typename enable_if_c<is_error_code_enum<E>::value || 508 is_error_condition_enum<E>::value, bool>::type 509 operator ==(ErrorOr<T> &Err, E Code) { 510 return error_code(Err) == Code; 511 } 512 } // end namespace llvm 513 514 #endif 515