[llvm] r264479 - [Support] Switch to RAII helper for error-as-out-parameter idiom.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 25 16:54:32 PDT 2016
Author: lhames
Date: Fri Mar 25 18:54:32 2016
New Revision: 264479
URL: http://llvm.org/viewvc/llvm-project?rev=264479&view=rev
Log:
[Support] Switch to RAII helper for error-as-out-parameter idiom.
As discussed on the llvm-commits thread for r264467.
Modified:
llvm/trunk/include/llvm/Support/Error.h
llvm/trunk/lib/Object/MachOObjectFile.cpp
llvm/trunk/unittests/Support/ErrorTest.cpp
Modified: llvm/trunk/include/llvm/Support/Error.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Error.h?rev=264479&r1=264478&r2=264479&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Error.h (original)
+++ llvm/trunk/include/llvm/Support/Error.h Fri Mar 25 18:54:32 2016
@@ -143,13 +143,6 @@ public:
/// constructor, but should be preferred for readability where possible.
static Error success() { return Error(); }
- /// Create a 'pre-checked' success value suitable for use as an out-parameter.
- static Error errorForOutParameter() {
- Error Err;
- (void)!!Err;
- return Err;
- }
-
// Errors are not copy-constructable.
Error(const Error &Other) = delete;
@@ -552,6 +545,36 @@ inline void consumeError(Error Err) {
handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
}
+/// Helper for Errors used as out-parameters.
+///
+/// This helper is for use with the Error-as-out-parameter idiom, where an error
+/// is passed to a function or method by reference, rather than being returned.
+/// In such cases it is helpful to set the checked bit on entry to the function
+/// so that the error can be written to (unchecked Errors abort on assignment)
+/// and clear the checked bit on exit so that clients cannot accidentally forget
+/// to check the result. This helper performs these actions automatically using
+/// RAII:
+///
+/// Result foo(Error &Err) {
+/// ErrorAsOutParameter ErrAsOutParam(Err); // 'Checked' flag set
+/// // <body of foo>
+/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
+/// }
+class ErrorAsOutParameter {
+public:
+ ErrorAsOutParameter(Error &Err) : Err(Err) {
+ // Raise the checked bit if Err is success.
+ (void)!!Err;
+ }
+ ~ErrorAsOutParameter() {
+ // Clear the checked bit.
+ if (!Err)
+ Err = Error::success();
+ }
+private:
+ Error &Err;
+};
+
/// Tagged union holding either a T or a Error.
///
/// This class parallels ErrorOr, but replaces error_code with Error. Since
Modified: llvm/trunk/lib/Object/MachOObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/MachOObjectFile.cpp?rev=264479&r1=264478&r2=264479&view=diff
==============================================================================
--- llvm/trunk/lib/Object/MachOObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/MachOObjectFile.cpp Fri Mar 25 18:54:32 2016
@@ -246,7 +246,7 @@ static Error parseSegmentLoadCommand(
Expected<std::unique_ptr<MachOObjectFile>>
MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
bool Is64Bits) {
- Error Err = Error::errorForOutParameter();
+ Error Err;
std::unique_ptr<MachOObjectFile> Obj(
new MachOObjectFile(std::move(Object), IsLittleEndian,
Is64Bits, Err));
@@ -262,7 +262,7 @@ MachOObjectFile::MachOObjectFile(MemoryB
DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr),
DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr),
HasPageZeroSegment(false) {
-
+ ErrorAsOutParameter ErrAsOutParam(Err);
if (is64Bit())
parseHeader(this, Header64, Err);
else
Modified: llvm/trunk/unittests/Support/ErrorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/ErrorTest.cpp?rev=264479&r1=264478&r2=264479&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/ErrorTest.cpp (original)
+++ llvm/trunk/unittests/Support/ErrorTest.cpp Fri Mar 25 18:54:32 2016
@@ -105,12 +105,32 @@ TEST(Error, UncheckedSuccess) {
}
#endif
-// Test that errors to be used as out parameters are implicitly checked (
-// and thus destruct quietly).
-TEST(Error, ErrorAsOutParameter) {
- Error E = Error::errorForOutParameter();
+// ErrorAsOutParameter tester.
+void errAsOutParamHelper(Error &Err) {
+ ErrorAsOutParameter ErrAsOutParam(Err);
+ // Verify that checked flag is raised - assignment should not crash.
+ Err = Error::success();
+ // Raise the checked bit manually - caller should still have to test the
+ // error.
+ (void)!!Err;
}
+// Test that ErrorAsOutParameter sets the checked flag on construction.
+TEST(Error, ErrorAsOutParameterChecked) {
+ Error E;
+ errAsOutParamHelper(E);
+ (void)!!E;
+}
+
+// Test that ErrorAsOutParameter clears the checked flag on destruction.
+#ifndef NDEBUG
+TEST(Error, ErrorAsOutParameterUnchecked) {
+ EXPECT_DEATH({ Error E; errAsOutParamHelper(E); },
+ "Program aborted due to an unhandled Error:")
+ << "ErrorAsOutParameter did not clear the checked flag on destruction.";
+}
+#endif
+
// Check that we abort on unhandled failure cases. (Force conversion to bool
// to make sure that we don't accidentally treat checked errors as handled).
// Test runs in debug mode only.
More information about the llvm-commits
mailing list