llvm.org GIT mirror llvm / f94b348
Simplify ErrorOr. ErrorOr had quiet a bit of complexity and indirection to be able to hold a user type with the error. That feature is not used anymore. This patch removes it, it will live in svn history if we ever need it again. If we do need it again, IMHO there is one thing that should be done differently: Holding extra info in the error is not a property a function also returning a value or not. The ability to hold extra info should be in the error type and ErrorOr templated over it so that we don't need the funny looking ErrorOr<void>. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194030 91177308-0d34-0410-b5e6-96231b3b80d8 Rafael Espindola 5 years ago
2 changed file(s) with 5 addition(s) and 252 deletion(s). Raw diff Collapse all Expand all
2626 #endif
2727
2828 namespace llvm {
29 struct ErrorHolderBase {
30 error_code Error;
31 uint16_t RefCount;
32 bool HasUserData;
33
34 ErrorHolderBase() : RefCount(1) {}
35
36 void acquire() {
37 ++RefCount;
38 }
39
40 void release() {
41 if (--RefCount == 0)
42 delete this;
43 }
44
45 protected:
46 virtual ~ErrorHolderBase() {}
47 };
48
49 template
50 struct ErrorHolder : ErrorHolderBase {
51 #if LLVM_HAS_RVALUE_REFERENCES
52 ErrorHolder(T &&UD) : UserData(llvm_move(UD)) {}
53 #else
54 ErrorHolder(T &UD) : UserData(UD) {}
55 #endif
56 T UserData;
57 };
58
59 template struct ErrorOrUserDataTraits : llvm::false_type {};
60
6129 #if LLVM_HAS_CXX11_TYPETRAITS && LLVM_HAS_RVALUE_REFERENCES
6230 template
6331 typename std::enable_if< std::is_constructible::value
11078 /// buffer->write("adena");
11179 /// \endcode
11280 ///
113 /// ErrorOr also supports user defined data for specific error_codes. To use
114 /// this feature you must first add a template specialization of
115 /// ErrorOrUserDataTraits derived from std::true_type for your type in the lld
116 /// namespace. This specialization must have a static error_code error()
117 /// function that returns the error_code this data is used with.
118 ///
119 /// getError() may be called to get either the stored user data, or
120 /// a default constructed UserData if none was stored.
121 ///
122 /// Example:
123 /// \code
124 /// struct InvalidArgError {
125 /// InvalidArgError() {}
126 /// InvalidArgError(std::string S) : ArgName(S) {}
127 /// std::string ArgName;
128 /// };
129 ///
130 /// namespace llvm {
131 /// template<>
132 /// struct ErrorOrUserDataTraits : std::true_type {
133 /// static error_code error() {
134 /// return make_error_code(errc::invalid_argument);
135 /// }
136 /// };
137 /// } // end namespace llvm
138 ///
139 /// using namespace llvm;
140 ///
141 /// ErrorOr foo() {
142 /// return InvalidArgError("adena");
143 /// }
144 ///
145 /// int main() {
146 /// auto a = foo();
147 /// if (!a && error_code(a) == errc::invalid_argument)
148 /// llvm::errs() << a.getError().ArgName << "\n";
149 /// }
150 /// \endcode
15181 ///
15282 /// An implicit conversion to bool provides a way to check if there was an
15383 /// error. The unary * and -> operators provide pointer like access to the
184114 is_error_condition_enum::value,
185115 void *>::type = 0)
186116 : HasError(true), IsValid(true) {
187 Error = new ErrorHolderBase;
188 Error->Error = make_error_code(ErrorCode);
189 Error->HasUserData = false;
117 Error = make_error_code(ErrorCode);
190118 }
191119
192120 ErrorOr(llvm::error_code EC) : HasError(true), IsValid(true) {
193 Error = new ErrorHolderBase;
194 Error->Error = EC;
195 Error->HasUserData = false;
196 }
197
198 template
199 ErrorOr(UserDataT UD, typename
200 enable_if_c::value>::type* = 0)
201 : HasError(true), IsValid(true) {
202 Error = new ErrorHolder(llvm_move(UD));
203 Error->Error = ErrorOrUserDataTraits::error();
204 Error->HasUserData = true;
121 Error = EC;
205122 }
206123
207124 ErrorOr(T Val) : HasError(false), IsValid(true) {
253170 ~ErrorOr() {
254171 if (!IsValid)
255172 return;
256 if (HasError)
257 Error->release();
258 else
173 if (!HasError)
259174 get()->~storage_type();
260 }
261
262 template
263 ET getError() const {
264 assert(IsValid && "Cannot get the error of a default constructed ErrorOr!");
265 assert(HasError && "Cannot get an error if none exists!");
266 assert(ErrorOrUserDataTraits::error() == Error->Error &&
267 "Incorrect user error data type for error!");
268 if (!Error->HasUserData)
269 return ET();
270 return reinterpret_cast*>(Error)->UserData;
271175 }
272176
273177 typedef void (*unspecified_bool_type)();
281185
282186 operator llvm::error_code() const {
283187 assert(IsValid && "Can't do anything on a default constructed ErrorOr!");
284 return HasError ? Error->Error : llvm::error_code::success();
188 return HasError ? Error : llvm::error_code::success();
285189 }
286190
287191 pointer operator ->() {
307211 // Get other's error.
308212 Error = Other.Error;
309213 HasError = true;
310 Error->acquire();
311214 }
312215 }
313216
384287
385288 union {
386289 AlignedCharArrayUnion TStorage;
387 ErrorHolderBase *Error;
290 error_code Error;
388291 };
389292 bool HasError : 1;
390293 bool IsValid : 1;
391 };
392
393 // ErrorOr specialization for void.
394 template <>
395 class ErrorOr {
396 public:
397 ErrorOr() : Error(0, 0) {}
398
399 template
400 ErrorOr(E ErrorCode, typename enable_if_c::value ||
401 is_error_condition_enum::value,
402 void *> ::type = 0)
403 : Error(0, 0) {
404 error_code EC = make_error_code(ErrorCode);
405 if (EC == errc::success) {
406 Error.setInt(1);
407 return;
408 }
409 ErrorHolderBase *EHB = new ErrorHolderBase;
410 EHB->Error = EC;
411 EHB->HasUserData = false;
412 Error.setPointer(EHB);
413 }
414
415 ErrorOr(llvm::error_code EC) : Error(0, 0) {
416 if (EC == errc::success) {
417 Error.setInt(1);
418 return;
419 }
420 ErrorHolderBase *E = new ErrorHolderBase;
421 E->Error = EC;
422 E->HasUserData = false;
423 Error.setPointer(E);
424 }
425
426 template
427 ErrorOr(UserDataT UD, typename
428 enable_if_c::value>::type* = 0)
429 : Error(0, 0) {
430 ErrorHolderBase *E = new ErrorHolder(llvm_move(UD));
431 E->Error = ErrorOrUserDataTraits::error();
432 E->HasUserData = true;
433 Error.setPointer(E);
434 }
435
436 ErrorOr(const ErrorOr &Other) : Error(0, 0) {
437 Error = Other.Error;
438 if (Other.Error.getPointer()->Error) {
439 Error.getPointer()->acquire();
440 }
441 }
442
443 ErrorOr &operator =(const ErrorOr &Other) {
444 if (this == &Other)
445 return *this;
446
447 this->~ErrorOr();
448 new (this) ErrorOr(Other);
449
450 return *this;
451 }
452
453 #if LLVM_HAS_RVALUE_REFERENCES
454 ErrorOr(ErrorOr &&Other) : Error(0) {
455 // Get other's error.
456 Error = Other.Error;
457 // Tell other not to do any destruction.
458 Other.Error.setPointer(0);
459 }
460
461 ErrorOr &operator =(ErrorOr &&Other) {
462 if (this == &Other)
463 return *this;
464
465 this->~ErrorOr();
466 new (this) ErrorOr(std::move(Other));
467
468 return *this;
469 }
470 #endif
471
472 ~ErrorOr() {
473 if (Error.getPointer())
474 Error.getPointer()->release();
475 }
476
477 template
478 ET getError() const {
479 assert(ErrorOrUserDataTraits::error() == *this &&
480 "Incorrect user error data type for error!");
481 if (!Error.getPointer()->HasUserData)
482 return ET();
483 return reinterpret_cast *>(
484 Error.getPointer())->UserData;
485 }
486
487 typedef void (*unspecified_bool_type)();
488 static void unspecified_bool_true() {}
489
490 /// \brief Return false if there is an error.
491 operator unspecified_bool_type() const {
492 return Error.getInt() ? unspecified_bool_true : 0;
493 }
494
495 operator llvm::error_code() const {
496 return Error.getInt() ? make_error_code(errc::success)
497 : Error.getPointer()->Error;
498 }
499
500 private:
501 // If the bit is 1, the error is success.
502 llvm::PointerIntPair Error;
503294 };
504295
505296 template
4444 *a = 42;
4545 EXPECT_EQ(42, x);
4646
47 EXPECT_FALSE(ErrorOr(errc::broken_pipe));
48 EXPECT_TRUE(ErrorOr(errc::success));
49
5047 #if LLVM_HAS_CXX11_STDLIB
5148 // Move only types.
5249 EXPECT_EQ(3, **t3());
6663 #endif
6764 }
6865 } // end anon namespace
69
70 struct InvalidArgError {
71 InvalidArgError() {}
72 InvalidArgError(std::string S) : ArgName(S) {}
73 std::string ArgName;
74 };
75
76 namespace llvm {
77 template<>
78 struct ErrorOrUserDataTraits : true_type {
79 static error_code error() {
80 return make_error_code(errc::invalid_argument);
81 }
82 };
83 } // end namespace llvm
84
85 ErrorOr t4() {
86 return InvalidArgError("adena");
87 }
88
89 ErrorOr t5() {
90 return InvalidArgError("pie");
91 }
92
93 namespace {
94 TEST(ErrorOr, UserErrorData) {
95 ErrorOr a = t4();
96 EXPECT_EQ(errc::invalid_argument, a);
97 EXPECT_EQ("adena", t4().getError().ArgName);
98
99 ErrorOr b = t5();
100 EXPECT_EQ(errc::invalid_argument, b);
101 EXPECT_EQ("pie", b.getError().ArgName);
102 }
103 } // end anon namespace