From 580ca237db3db87264b44758a89d97a7bb445ff1 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Tue, 5 Apr 2016 19:57:03 +0000 Subject: [Support] Add a checked flag to Expected, require checks before access or destruction. This makes the Expected class behave like Error, even when in success mode. Expected values must be checked to see whether they contain an error prior to being dereferenced, assigned to, or destructed. llvm-svn: 265446 --- llvm/unittests/Support/ErrorTest.cpp | 50 +++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'llvm/unittests/Support/ErrorTest.cpp') diff --git a/llvm/unittests/Support/ErrorTest.cpp b/llvm/unittests/Support/ErrorTest.cpp index 7d71477..6a1400a 100644 --- a/llvm/unittests/Support/ErrorTest.cpp +++ b/llvm/unittests/Support/ErrorTest.cpp @@ -401,13 +401,47 @@ TEST(Error, ExitOnError) { << "exitOnError returned an unexpected error result"; } -// Test Expected in success mode. -TEST(Error, ExpectedInSuccessMode) { +// Test Checked Expected in success mode. +TEST(Error, CheckedExpectedInSuccessMode) { Expected A = 7; EXPECT_TRUE(!!A) << "Expected with non-error value doesn't convert to 'true'"; + // Access is safe in second test, since we checked the error in the first. EXPECT_EQ(*A, 7) << "Incorrect Expected non-error value"; } +// Test Unchecked Expected in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +#ifndef NDEBUG +TEST(Error, UncheckedExpectedInSuccessModeDestruction) { + EXPECT_DEATH({ Expected A = 7; }, + "Expected must be checked before access or destruction.") + << "Unchecekd Expected success value did not cause an abort()."; +} +#endif + +// Test Unchecked Expected in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +#ifndef NDEBUG +TEST(Error, UncheckedExpectedInSuccessModeAccess) { + EXPECT_DEATH({ Expected A = 7; *A; }, + "Expected must be checked before access or destruction.") + << "Unchecekd Expected success value did not cause an abort()."; +} +#endif + +// Test Unchecked Expected in success mode. +// We expect this to blow up the same way Error would. +// Test runs in debug mode only. +#ifndef NDEBUG +TEST(Error, UncheckedExpectedInSuccessModeAssignment) { + EXPECT_DEATH({ Expected A = 7; A = 7; }, + "Expected must be checked before access or destruction.") + << "Unchecekd Expected success value did not cause an abort()."; +} +#endif + // Test Expected in failure mode. TEST(Error, ExpectedInFailureMode) { Expected A = make_error(42); @@ -423,7 +457,7 @@ TEST(Error, ExpectedInFailureMode) { #ifndef NDEBUG TEST(Error, AccessExpectedInFailureMode) { Expected A = make_error(42); - EXPECT_DEATH(*A, "!HasError && \"Cannot get value when an error exists!\"") + EXPECT_DEATH(*A, "Expected must be checked before access or destruction.") << "Incorrect Expected error value"; consumeError(A.takeError()); } @@ -435,7 +469,7 @@ TEST(Error, AccessExpectedInFailureMode) { #ifndef NDEBUG TEST(Error, UnhandledExpectedInFailureMode) { EXPECT_DEATH({ Expected A = make_error(42); }, - "Program aborted due to an unhandled Error:") + "Expected must be checked before access or destruction.") << "Unchecked Expected failure value did not cause an abort()"; } #endif @@ -446,10 +480,18 @@ TEST(Error, ExpectedCovariance) { class D : public B {}; Expected A1(Expected(nullptr)); + // Check A1 by converting to bool before assigning to it. + (void)!!A1; A1 = Expected(nullptr); + // Check A1 again before destruction. + (void)!!A1; Expected> A2(Expected>(nullptr)); + // Check A2 by converting to bool before assigning to it. + (void)!!A2; A2 = Expected>(nullptr); + // Check A2 again before destruction. + (void)!!A2; } TEST(Error, ErrorCodeConversions) { -- cgit v1.1