public:
/// Create a success value. Prefer using 'Error::success()' for readability
/// where possible.
- Error() {
+ Error() : Payload(nullptr) {
setPtr(nullptr);
setChecked(false);
}
/// Move-construct an error value. The newly constructed error is considered
/// unchecked, even if the source error had been checked. The original error
/// becomes a checked Success value, regardless of its original state.
- Error(Error &&Other) {
+ Error(Error &&Other) : Payload(nullptr) {
setChecked(true);
*this = std::move(Other);
}
}
ErrorInfoBase *getPtr() const {
-#ifndef NDEBUG
- return PayloadAndCheckedBit.getPointer();
-#else
- return Payload;
-#endif
+ return reinterpret_cast<ErrorInfoBase*>(
+ reinterpret_cast<uintptr_t>(Payload) &
+ ~static_cast<uintptr_t>(0x1));
}
void setPtr(ErrorInfoBase *EI) {
#ifndef NDEBUG
- PayloadAndCheckedBit.setPointer(EI);
+ Payload = reinterpret_cast<ErrorInfoBase*>(
+ (reinterpret_cast<uintptr_t>(EI) &
+ ~static_cast<uintptr_t>(0x1)) |
+ (reinterpret_cast<uintptr_t>(Payload) & 0x1));
#else
Payload = EI;
#endif
bool getChecked() const {
#ifndef NDEBUG
- return PayloadAndCheckedBit.getInt();
+ return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0;
#else
return true;
#endif
}
void setChecked(bool V) {
-#ifndef NDEBUG
- PayloadAndCheckedBit.setInt(V);
-#endif
+ Payload = reinterpret_cast<ErrorInfoBase*>(
+ (reinterpret_cast<uintptr_t>(Payload) &
+ ~static_cast<uintptr_t>(0x1)) |
+ (V ? 0 : 1));
}
std::unique_ptr<ErrorInfoBase> takePayload() {
return Tmp;
}
-#ifndef NDEBUG
- PointerIntPair<ErrorInfoBase *, 1> PayloadAndCheckedBit;
-#else
ErrorInfoBase *Payload;
-#endif
};
/// Make a Error instance representing failure using the given error info
public:
/// Create an Expected<T> error value from the given Error.
Expected(Error Err)
- : HasError(true)
+ : HasError(true),
#ifndef NDEBUG
- ,
- Checked(false)
+ // Expected is unchecked upon construction in Debug builds.
+ Unchecked(true)
+#else
+ // Expected's unchecked flag is set to false in Release builds. This
+ // allows Expected values constructed in a Release build library to be
+ // consumed by a Debug build application.
+ Unchecked(false)
#endif
+
{
assert(Err && "Cannot create Expected<T> from Error success value.");
new (getErrorStorage()) Error(std::move(Err));
Expected(OtherT &&Val,
typename std::enable_if<std::is_convertible<OtherT, T>::value>::type
* = nullptr)
- : HasError(false)
+ : HasError(false),
#ifndef NDEBUG
- ,
- Checked(false)
+ // Expected is unchecked upon construction in Debug builds.
+ Unchecked(true)
+#else
+ // Expected's 'unchecked' flag is set to false in Release builds. This
+ // allows Expected values constructed in a Release build library to be
+ // consumed by a Debug build application.
+ Unchecked(false)
#endif
{
new (getStorage()) storage_type(std::forward<OtherT>(Val));
/// \brief Return false if there is an error.
explicit operator bool() {
#ifndef NDEBUG
- Checked = !HasError;
+ Unchecked = HasError;
#endif
return !HasError;
}
/// be made on the Expected<T> vaule.
Error takeError() {
#ifndef NDEBUG
- Checked = true;
+ Unchecked = false;
#endif
return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
}
template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) {
HasError = Other.HasError;
-
-#ifndef NDEBUG
- Checked = false;
- Other.Checked = true;
-#endif
+ Unchecked = true;
+ Other.Unchecked = false;
if (!HasError)
new (getStorage()) storage_type(std::move(*Other.getStorage()));
void assertIsChecked() {
#ifndef NDEBUG
- if (!Checked) {
+ if (Unchecked) {
dbgs() << "Expected<T> must be checked before access or destruction.\n";
if (HasError) {
dbgs() << "Unchecked Expected<T> contained error:\n";
AlignedCharArrayUnion<error_type> ErrorStorage;
};
bool HasError : 1;
-#ifndef NDEBUG
- bool Checked : 1;
-#endif
+ bool Unchecked : 1;
};
/// This class wraps a std::error_code in a Error.