diff options
author | DeLesley Hutchins <delesley@google.com> | 2013-10-04 21:28:06 +0000 |
---|---|---|
committer | DeLesley Hutchins <delesley@google.com> | 2013-10-04 21:28:06 +0000 |
commit | 66540857c08de7f1be9bea48381548d3942cf9d1 (patch) | |
tree | f7b37bfb773f09b0a81afe3745ae7702fb012b59 /test/SemaCXX/warn-consumed-analysis.cpp | |
parent | 1cd6fab3930d5c058c201895654c6b0bd6ecb8c1 (diff) | |
download | clang-66540857c08de7f1be9bea48381548d3942cf9d1.tar.gz |
Consumed Analysis: Change callable_when so that it can take a list of states
that a function can be called in. This reduced the total number of annotations
needed and makes writing more complicated behaviour less burdensome.
Patch by chriswails@gmail.com.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191983 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/SemaCXX/warn-consumed-analysis.cpp')
-rw-r--r-- | test/SemaCXX/warn-consumed-analysis.cpp | 265 |
1 files changed, 207 insertions, 58 deletions
diff --git a/test/SemaCXX/warn-consumed-analysis.cpp b/test/SemaCXX/warn-consumed-analysis.cpp index 8d4bff705c..c33e3a197a 100644 --- a/test/SemaCXX/warn-consumed-analysis.cpp +++ b/test/SemaCXX/warn-consumed-analysis.cpp @@ -1,10 +1,12 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s -#define CALLABLE_WHEN_UNCONSUMED __attribute__ ((callable_when_unconsumed)) -#define CONSUMABLE(state) __attribute__ ((consumable(state))) -#define CONSUMES __attribute__ ((consumes)) -#define RETURN_TYPESTATE(state) __attribute__ ((return_typestate(state))) -#define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed)) +// TODO: Switch to using macros for the expected warnings. + +#define CALLABLE_WHEN(...) __attribute__ ((callable_when(__VA_ARGS__))) +#define CONSUMABLE(state) __attribute__ ((consumable(state))) +#define CONSUMES __attribute__ ((consumes)) +#define RETURN_TYPESTATE(state) __attribute__ ((return_typestate(state))) +#define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed)) typedef decltype(nullptr) nullptr_t; @@ -30,8 +32,9 @@ class CONSUMABLE(unconsumed) ConsumableClass { ConsumableClass<T>& operator=(ConsumableClass<U> &&other); void operator()(int a) CONSUMES; - void operator*() const CALLABLE_WHEN_UNCONSUMED; - void unconsumedCall() const CALLABLE_WHEN_UNCONSUMED; + void operator*() const CALLABLE_WHEN("unconsumed"); + void unconsumedCall() const CALLABLE_WHEN("unconsumed"); + void callableWhenUnknown() const CALLABLE_WHEN("unconsumed", "unknown"); bool isValid() const TESTS_UNCONSUMED; operator bool() const TESTS_UNCONSUMED; @@ -47,7 +50,9 @@ void baf0(const ConsumableClass<int> var); void baf1(const ConsumableClass<int> &var); void baf2(const ConsumableClass<int> *var); -void baf3(ConsumableClass<int> &&var); +void baf3(ConsumableClass<int> &var); +void baf4(ConsumableClass<int> *var); +void baf5(ConsumableClass<int> &&var); ConsumableClass<int> returnsUnconsumed() { return ConsumableClass<int>(); // expected-warning {{return value not in expected state; expected 'unconsumed', observed 'consumed'}} @@ -58,39 +63,41 @@ ConsumableClass<int> returnsConsumed() { return ConsumableClass<int>(); } +ConsumableClass<int> returnsUnknown() RETURN_TYPESTATE(unknown); + void testInitialization() { ConsumableClass<int> var0; ConsumableClass<int> var1 = ConsumableClass<int>(); var0 = ConsumableClass<int>(); - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} if (var0.isValid()) { *var0; *var1; } else { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} } } void testTempValue() { - *ConsumableClass<int>(); // expected-warning {{invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}} + *ConsumableClass<int>(); // expected-warning {{invalid invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}} } void testSimpleRValueRefs() { ConsumableClass<int> var0; ConsumableClass<int> var1(42); - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; var0 = static_cast<ConsumableClass<int>&&>(var1); *var0; - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } void testIfStmt() { @@ -99,11 +106,11 @@ void testIfStmt() { if (var.isValid()) { *var; } else { - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } if (!var.isValid()) { - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } else { *var; } @@ -111,17 +118,17 @@ void testIfStmt() { if (var) { // Empty } else { - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } if (var != nullptr) { // Empty } else { - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } } -void testComplexConditionals() { +void testComplexConditionals0() { ConsumableClass<int> var0, var1, var2; if (var0 && var1) { @@ -129,8 +136,8 @@ void testComplexConditionals() { *var1; } else { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } if (var0 || var1) { @@ -138,8 +145,8 @@ void testComplexConditionals() { *var1; } else { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } if (var0 && !var1) { @@ -147,13 +154,13 @@ void testComplexConditionals() { *var1; } else { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } if (var0 || !var1) { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } else { *var0; @@ -161,8 +168,8 @@ void testComplexConditionals() { } if (!var0 && !var1) { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } else { *var0; @@ -170,8 +177,8 @@ void testComplexConditionals() { } if (!var0 || !var1) { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } else { *var0; @@ -179,8 +186,8 @@ void testComplexConditionals() { } if (!(var0 && var1)) { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } else { *var0; @@ -188,8 +195,8 @@ void testComplexConditionals() { } if (!(var0 || var1)) { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } else { *var0; @@ -202,9 +209,9 @@ void testComplexConditionals() { *var2; } else { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - *var2; // expected-warning {{invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}} } #if 0 @@ -215,9 +222,115 @@ void testComplexConditionals() { *var2; } else { - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} - *var2; // expected-warning {{invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}} + } +#endif +} + +void testComplexConditionals1() { + ConsumableClass<int> var0, var1, var2; + + // Coerce all variables into the unknown state. + baf3(var0); + baf3(var1); + baf3(var2); + + if (var0 && var1) { + *var0; + *var1; + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + } + + if (var0 || var1) { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + } + + if (var0 && !var1) { + *var0; + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + } + + if (var0 || !var1) { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; + } + + if (!var0 && !var1) { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + } + + if (!(var0 || var1)) { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + } + + if (!var0 || !var1) { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + + } else { + *var0; + *var1; + } + + if (!(var0 && var1)) { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + + } else { + *var0; + *var1; + } + + if (var0 && var1 && var2) { + *var0; + *var1; + *var2; + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'unknown' state}} + } + +#if 0 + // FIXME: Get this test to pass. + if (var0 || var1 || var2) { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'unknown' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'unknown' state}} + *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'unknown' state}} + + } else { + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var2; // expected-warning {{invalid invocation of method 'operator*' on object 'var2' while it is in the 'consumed' state}} } #endif } @@ -226,7 +339,7 @@ void testStateChangeInBranch() { ConsumableClass<int> var; // Make var enter the 'unknown' state. - baf1(var); + baf3(var); if (!var) { var = ConsumableClass<int>(42); @@ -259,8 +372,34 @@ void testCallingConventions() { baf2(&var); *var; - baf3(static_cast<ConsumableClass<int>&&>(var)); - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + baf3(var); + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} + + var = ConsumableClass<int>(42); + baf4(&var); + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} + + var = ConsumableClass<int>(42); + baf5(static_cast<ConsumableClass<int>&&>(var)); + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} +} + +void testConstAndNonConstMemberFunctions() { + ConsumableClass<int> var(42); + + var.constCall(); + *var; + + var.nonconstCall(); + *var; +} + +void testFunctionParam0(ConsumableClass<int> param) { + *param; +} + +void testFunctionParam1(ConsumableClass<int> ¶m) { + *param; // expected-warning {{invalid invocation of method 'operator*' on object 'param' while it is in the 'unknown' state}} } void testReturnStates() { @@ -270,24 +409,34 @@ void testReturnStates() { *var; var = returnsConsumed(); - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} +} + +void testCallableWhen() { + ConsumableClass<int> var(42); + + *var; + + baf3(var); + + var.callableWhenUnknown(); } void testMoveAsignmentish() { ConsumableClass<int> var0; ConsumableClass<long> var1(42); - *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} + *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; var0 = static_cast<ConsumableClass<long>&&>(var1); *var0; - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} var1 = ConsumableClass<long>(42); var1 = nullptr; - *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} + *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } void testConditionalMerge() { @@ -297,7 +446,7 @@ void testConditionalMerge() { // Empty } - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} if (var.isValid()) { // Empty @@ -305,7 +454,7 @@ void testConditionalMerge() { // Empty } - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConsumes0() { @@ -315,13 +464,13 @@ void testConsumes0() { var.consume(); - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConsumes1() { ConsumableClass<int> var(nullptr); - *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConsumes2() { @@ -330,10 +479,10 @@ void testConsumes2() { var.unconsumedCall(); var(6); - var.unconsumedCall(); // expected-warning {{invocation of method 'unconsumedCall' on object 'var' while it is in the 'consumed' state}} + var.unconsumedCall(); // expected-warning {{invalid invocation of method 'unconsumedCall' on object 'var' while it is in the 'consumed' state}} } -void testNonsenseState() { +void testUnreachableBlock() { ConsumableClass<int> var(42); if (var) { @@ -349,10 +498,10 @@ void testSimpleForLoop() { ConsumableClass<int> var; for (int i = 0; i < 10; ++i) { - *var; + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} } - *var; + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} } void testSimpleWhileLoop() { @@ -361,9 +510,9 @@ void testSimpleWhileLoop() { ConsumableClass<int> var; while (i < 10) { - *var; + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} ++i; } - *var; + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} } |