| // RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -fcxx-exceptions -std=c++11 %s |
| |
| // TODO: Switch to using macros for the expected warnings. |
| |
| #define CALLABLE_WHEN(...) __attribute__ ((callable_when(__VA_ARGS__))) |
| #define CONSUMABLE(state) __attribute__ ((consumable(state))) |
| #define PARAM_TYPESTATE(state) __attribute__ ((param_typestate(state))) |
| #define RETURN_TYPESTATE(state) __attribute__ ((return_typestate(state))) |
| #define SET_TYPESTATE(state) __attribute__ ((set_typestate(state))) |
| #define TEST_TYPESTATE(state) __attribute__ ((test_typestate(state))) |
| |
| typedef decltype(nullptr) nullptr_t; |
| |
| template <typename T> |
| class CONSUMABLE(unconsumed) ConsumableClass { |
| T var; |
| |
| public: |
| ConsumableClass(); |
| ConsumableClass(nullptr_t p) RETURN_TYPESTATE(consumed); |
| ConsumableClass(T val) RETURN_TYPESTATE(unconsumed); |
| ConsumableClass(ConsumableClass<T> &other); |
| ConsumableClass(ConsumableClass<T> &&other); |
| |
| ConsumableClass<T>& operator=(ConsumableClass<T> &other); |
| ConsumableClass<T>& operator=(ConsumableClass<T> &&other); |
| ConsumableClass<T>& operator=(nullptr_t) SET_TYPESTATE(consumed); |
| |
| template <typename U> |
| ConsumableClass<T>& operator=(ConsumableClass<U> &other); |
| |
| template <typename U> |
| ConsumableClass<T>& operator=(ConsumableClass<U> &&other); |
| |
| void operator()(int a) SET_TYPESTATE(consumed); |
| void operator*() const CALLABLE_WHEN("unconsumed"); |
| void unconsumedCall() const CALLABLE_WHEN("unconsumed"); |
| void callableWhenUnknown() const CALLABLE_WHEN("unconsumed", "unknown"); |
| |
| bool isValid() const TEST_TYPESTATE(unconsumed); |
| operator bool() const TEST_TYPESTATE(unconsumed); |
| bool operator!=(nullptr_t) const TEST_TYPESTATE(unconsumed); |
| bool operator==(nullptr_t) const TEST_TYPESTATE(consumed); |
| |
| void constCall() const; |
| void nonconstCall(); |
| |
| void consume() SET_TYPESTATE(consumed); |
| void unconsume() SET_TYPESTATE(unconsumed); |
| }; |
| |
| class CONSUMABLE(unconsumed) DestructorTester { |
| public: |
| DestructorTester(); |
| DestructorTester(int); |
| DestructorTester(nullptr_t) RETURN_TYPESTATE(unconsumed); |
| DestructorTester(DestructorTester &&); |
| |
| void operator*() CALLABLE_WHEN("unconsumed"); |
| |
| ~DestructorTester() CALLABLE_WHEN("consumed"); |
| |
| }; |
| |
| void dtByVal(DestructorTester); |
| void dtByValMarkUnconsumed(DestructorTester RETURN_TYPESTATE(unconsumed)); |
| |
| void baf0(const ConsumableClass<int> var); |
| void baf1(const ConsumableClass<int> &var); |
| void baf2(const ConsumableClass<int> *var); |
| |
| void baf3(ConsumableClass<int> var); |
| void baf4(ConsumableClass<int> &var); |
| void baf5(ConsumableClass<int> *var); |
| void baf6(ConsumableClass<int> &&var); |
| |
| ConsumableClass<int> returnsUnconsumed() { |
| return ConsumableClass<int>(); // expected-warning {{return value not in expected state; expected 'unconsumed', observed 'consumed'}} |
| } |
| |
| ConsumableClass<int> returnsConsumed() RETURN_TYPESTATE(consumed); |
| ConsumableClass<int> returnsConsumed() { |
| return ConsumableClass<int>(); |
| } |
| |
| ConsumableClass<int> returnsUnknown() RETURN_TYPESTATE(unknown); |
| |
| void testInitialization() { |
| ConsumableClass<int> var0; |
| ConsumableClass<int> var1 = ConsumableClass<int>(); |
| ConsumableClass<int> var2(42); |
| ConsumableClass<int> var3(var2); // copy constructor |
| ConsumableClass<int> var4(var0); // copy consumed value |
| |
| *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; |
| *var3; |
| *var4; // expected-warning {{invalid invocation of method 'operator*' on object 'var4' while it is in the 'consumed' state}} |
| |
| var0 = ConsumableClass<int>(42); |
| *var0; |
| |
| var0 = var1; |
| *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} |
| |
| if (var0.isValid()) { |
| *var0; |
| *var1; |
| |
| } else { |
| *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} |
| } |
| } |
| |
| void testDestruction() { |
| DestructorTester D0(42), D1(42), D2; |
| |
| *D0; |
| *D1; |
| *D2; // expected-warning {{invalid invocation of method 'operator*' on object 'D2' while it is in the 'consumed' state}} |
| |
| D0.~DestructorTester(); // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}} |
| |
| return; // expected-warning {{invalid invocation of method '~DestructorTester' on object 'D0' while it is in the 'unconsumed' state}} \ |
| expected-warning {{invalid invocation of method '~DestructorTester' on object 'D1' while it is in the 'unconsumed' state}} |
| } |
| |
| void testDestructionByVal() { |
| { |
| // both the var and the temporary are consumed: |
| DestructorTester D0(nullptr); |
| dtByVal((DestructorTester &&)D0); |
| } |
| { |
| // the var is consumed but the temporary isn't: |
| DestructorTester D1(nullptr); |
| dtByValMarkUnconsumed((DestructorTester &&)D1); // expected-warning {{invalid invocation of method '~DestructorTester' on a temporary object while it is in the 'unconsumed' state}} |
| } |
| } |
| |
| void testTempValue() { |
| *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 {{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 {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} |
| } |
| |
| void testIfStmt() { |
| ConsumableClass<int> var; |
| |
| if (var.isValid()) { |
| *var; |
| } else { |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| } |
| |
| if (!var.isValid()) { |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| } else { |
| *var; |
| } |
| |
| if (var) { |
| // Empty |
| } else { |
| *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 {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| } |
| |
| if (var == nullptr) { |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| } else { |
| // Empty |
| } |
| } |
| |
| void testComplexConditionals0() { |
| ConsumableClass<int> var0, var1, var2; |
| |
| if (var0 && var1) { |
| *var0; |
| *var1; |
| |
| } 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; |
| |
| } 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; |
| |
| } 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; // 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; |
| *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; |
| *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; |
| *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; |
| *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; |
| *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 '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 |
| // FIXME: Get this test to pass. |
| if (var0 || var1 || var2) { |
| *var0; |
| *var1; |
| *var2; |
| |
| } 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 |
| } |
| |
| void testComplexConditionals1() { |
| ConsumableClass<int> var0, var1, var2; |
| |
| // Coerce all variables into the unknown state. |
| baf4(var0); |
| baf4(var1); |
| baf4(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 |
| } |
| |
| void testStateChangeInBranch() { |
| ConsumableClass<int> var; |
| |
| // Make var enter the 'unknown' state. |
| baf4(var); |
| |
| if (!var) { |
| var = ConsumableClass<int>(42); |
| } |
| |
| *var; |
| } |
| |
| void testFunctionParam(ConsumableClass<int> param) { |
| |
| if (param.isValid()) { |
| *param; |
| } else { |
| *param; |
| } |
| |
| param = nullptr; |
| *param; // expected-warning {{invocation of method 'operator*' on object 'param' while it is in the 'consumed' state}} |
| } |
| |
| void testParamReturnTypestateCallee(bool cond, ConsumableClass<int> &Param RETURN_TYPESTATE(unconsumed)) { // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}} |
| |
| if (cond) { |
| Param.consume(); |
| return; // expected-warning {{parameter 'Param' not in expected state when the function returns: expected 'unconsumed', observed 'consumed'}} |
| } |
| |
| Param.consume(); |
| } |
| |
| void testRvalueRefParamReturnTypestateCallee(ConsumableClass<int> &&Param RETURN_TYPESTATE(unconsumed)) { |
| Param.unconsume(); |
| } |
| |
| void testParamReturnTypestateCaller() { |
| ConsumableClass<int> var; |
| |
| testParamReturnTypestateCallee(true, var); |
| testRvalueRefParamReturnTypestateCallee((ConsumableClass<int> &&)var); |
| |
| *var; |
| } |
| |
| void testParamTypestateCallee(ConsumableClass<int> Param0 PARAM_TYPESTATE(consumed), |
| ConsumableClass<int> &Param1 PARAM_TYPESTATE(consumed)) { |
| |
| *Param0; // expected-warning {{invalid invocation of method 'operator*' on object 'Param0' while it is in the 'consumed' state}} |
| *Param1; // expected-warning {{invalid invocation of method 'operator*' on object 'Param1' while it is in the 'consumed' state}} |
| } |
| |
| void testParamTypestateCaller() { |
| ConsumableClass<int> Var0, Var1(42); |
| |
| testParamTypestateCallee(Var0, Var1); // expected-warning {{argument not in expected state; expected 'consumed', observed 'unconsumed'}} |
| } |
| |
| |
| void consumeFunc(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed)); |
| struct ParamTest { |
| static void consumeFuncStatic(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed)); |
| void consumeFuncMeth(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed)); |
| void operator<<(ConsumableClass<int> P PARAM_TYPESTATE(unconsumed)); |
| }; |
| |
| void operator>>(ParamTest& pt, ConsumableClass<int> P PARAM_TYPESTATE(unconsumed)); |
| |
| |
| void testFunctionParams() { |
| // Make sure we handle the different kinds of functions. |
| ConsumableClass<int> P; |
| |
| consumeFunc(P); // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}} |
| ParamTest::consumeFuncStatic(P); // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}} |
| ParamTest pt; |
| pt.consumeFuncMeth(P); // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}} |
| pt << P; // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}} |
| pt >> P; // expected-warning {{argument not in expected state; expected 'unconsumed', observed 'consumed'}} |
| } |
| |
| void baf3(ConsumableClass<int> var) { |
| *var; |
| } |
| |
| void baf4(ConsumableClass<int> &var) { |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} |
| } |
| |
| void baf6(ConsumableClass<int> &&var) { |
| *var; |
| } |
| |
| void testCallingConventions() { |
| ConsumableClass<int> var(42); |
| |
| baf0(var); |
| *var; |
| |
| baf1(var); |
| *var; |
| |
| baf2(&var); |
| *var; |
| |
| baf3(var); |
| *var; |
| |
| 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(&var); |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} |
| |
| var = ConsumableClass<int>(42); |
| baf6(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() { |
| ConsumableClass<int> var; |
| |
| var = returnsUnconsumed(); |
| *var; |
| |
| var = returnsConsumed(); |
| *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; |
| |
| baf4(var); |
| |
| var.callableWhenUnknown(); |
| } |
| |
| void testMoveAsignmentish() { |
| ConsumableClass<int> var0; |
| ConsumableClass<long> var1(42); |
| |
| *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 {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} |
| |
| var1 = ConsumableClass<long>(42); |
| var1 = nullptr; |
| *var1; // expected-warning {{invalid invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} |
| } |
| |
| void testConditionalMerge() { |
| ConsumableClass<int> var; |
| |
| if (var.isValid()) { |
| // Empty |
| } |
| |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| |
| if (var.isValid()) { |
| // Empty |
| } else { |
| // Empty |
| } |
| |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| } |
| |
| void testSetTypestate() { |
| ConsumableClass<int> var(42); |
| |
| *var; |
| |
| var.consume(); |
| |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| |
| var.unconsume(); |
| |
| *var; |
| } |
| |
| void testConsumes0() { |
| ConsumableClass<int> var(nullptr); |
| |
| *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} |
| } |
| |
| void testConsumes1() { |
| ConsumableClass<int> var(42); |
| |
| var.unconsumedCall(); |
| var(6); |
| |
| var.unconsumedCall(); // expected-warning {{invalid invocation of method 'unconsumedCall' on object 'var' while it is in the 'consumed' state}} |
| } |
| |
| void testUnreachableBlock() { |
| ConsumableClass<int> var(42); |
| |
| if (var) { |
| *var; |
| } else { |
| *var; |
| } |
| |
| *var; |
| } |
| |
| |
| void testForLoop1() { |
| ConsumableClass<int> var0, var1(42); |
| |
| for (int i = 0; i < 10; ++i) { // expected-warning {{state of variable 'var1' must match at the entry and exit of loop}} |
| *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} |
| |
| *var1; |
| var1.consume(); |
| *var1; // expected-warning {{invalid 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}} |
| } |
| |
| void testWhileLoop1() { |
| int i = 10; |
| |
| ConsumableClass<int> var0, var1(42); |
| |
| while (i-- > 0) { // expected-warning {{state of variable 'var1' must match at the entry and exit of loop}} |
| *var0; // expected-warning {{invalid invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} |
| |
| *var1; |
| var1.consume(); |
| *var1; // expected-warning {{invalid 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}} |
| } |
| |
| // Tests if state information is correctly discarded for certain shapes of CFGs. |
| void testSwitchGOTO(void) { |
| int a; |
| |
| LABEL0: |
| switch (a) |
| case 0: |
| goto LABEL0; |
| |
| goto LABEL0; |
| } |
| |
| typedef const int*& IntegerPointerReference; |
| void testIsRValueRefishAndCanonicalType(IntegerPointerReference a) {} |
| |
| namespace ContinueICETest { |
| |
| bool cond1(); |
| bool cond2(); |
| |
| static void foo1() { |
| while (cond1()) { |
| if (cond2()) |
| continue; |
| } |
| } |
| |
| static void foo2() { |
| while (true) { |
| if (false) |
| continue; |
| } |
| } |
| |
| class runtime_error |
| { |
| public: |
| virtual ~runtime_error(); |
| }; |
| |
| void read(bool sf) { |
| while (sf) { |
| if(sf) throw runtime_error(); |
| } |
| } |
| |
| } // end namespace ContinueICETest |
| |
| |
| namespace StatusUseCaseTests { |
| |
| class CONSUMABLE(unconsumed) |
| __attribute__((consumable_auto_cast_state)) |
| __attribute__((consumable_set_state_on_read)) |
| Status { |
| int code; |
| |
| public: |
| static Status OK; |
| |
| Status() RETURN_TYPESTATE(consumed); |
| Status(int c) RETURN_TYPESTATE(unconsumed); |
| |
| Status(const Status &other); |
| Status(Status &&other); |
| |
| Status& operator=(const Status &other) CALLABLE_WHEN("unknown", "consumed"); |
| Status& operator=(Status &&other) CALLABLE_WHEN("unknown", "consumed"); |
| |
| bool operator==(const Status &other) const SET_TYPESTATE(consumed); |
| |
| bool check() const SET_TYPESTATE(consumed); |
| void ignore() const SET_TYPESTATE(consumed); |
| // Status& markAsChecked() { return *this; } |
| |
| void clear() CALLABLE_WHEN("unknown", "consumed") SET_TYPESTATE(consumed); |
| |
| ~Status() CALLABLE_WHEN("unknown", "consumed"); |
| |
| operator bool() const; // Will not consume the object. |
| }; |
| |
| |
| bool cond(); |
| Status doSomething(); |
| void handleStatus(const Status& s RETURN_TYPESTATE(consumed)); |
| void handleStatusRef(Status& s); |
| void handleStatusPtr(Status* s); |
| void handleStatusUnmarked(const Status& s); |
| |
| void log(const char* msg); |
| void fail() __attribute__((noreturn)); |
| void checkStat(const Status& s); |
| |
| |
| void testSimpleTemporaries0() { |
| doSomething(); // expected-warning {{invalid invocation of method '~Status' on a temporary object while it is in the 'unconsumed' state}} |
| } |
| |
| void testSimpleTemporaries1() { |
| doSomething().ignore(); |
| } |
| |
| void testSimpleTemporaries2() { |
| handleStatus(doSomething()); |
| } |
| |
| void testSimpleTemporaries3() { |
| Status s = doSomething(); |
| } // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}} |
| |
| void testTemporariesWithControlFlow(bool a) { |
| bool b = false || doSomething(); // expected-warning {{invalid invocation of method '~Status' on a temporary object while it is in the 'unconsumed' state}} |
| } |
| |
| Status testSimpleTemporariesReturn0() { |
| return doSomething(); |
| } |
| |
| Status testSimpleTemporariesReturn1() { |
| Status s = doSomething(); |
| return s; |
| } |
| |
| void testSimpleTemporaries4() { |
| Status s = doSomething(); |
| s.check(); |
| } |
| |
| void testSimpleTemporaries5() { |
| Status s = doSomething(); |
| s.clear(); // expected-warning {{invalid invocation of method 'clear' on object 's' while it is in the 'unconsumed' state}} |
| } |
| |
| void testSimpleTemporaries6() { |
| Status s1 = doSomething(); |
| handleStatus(s1); |
| |
| Status s2 = doSomething(); |
| handleStatusRef(s2); |
| |
| Status s3 = doSomething(); |
| handleStatusPtr(&s3); |
| |
| Status s4 = doSomething(); |
| handleStatusUnmarked(s4); |
| } |
| |
| void testSimpleTemporaries7() { |
| Status s; |
| s = doSomething(); |
| } // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}} |
| |
| void testTemporariesWithConditionals0() { |
| int a; |
| |
| Status s = doSomething(); |
| if (cond()) a = 0; |
| else a = 1; |
| } // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}} |
| |
| void testTemporariesWithConditionals1() { |
| int a; |
| |
| Status s = doSomething(); |
| if (cond()) a = 0; |
| else a = 1; |
| s.ignore(); |
| } |
| |
| void testTemporariesWithConditionals2() { |
| int a; |
| |
| Status s = doSomething(); |
| s.ignore(); |
| if (cond()) a = 0; |
| else a = 1; |
| } |
| |
| void testTemporariesWithConditionals3() { |
| Status s = doSomething(); |
| if (cond()) { |
| s.check(); |
| } |
| } |
| |
| void testTemporariesAndConstructors0() { |
| Status s(doSomething()); // Test the copy constructor. |
| s.check(); |
| } |
| |
| void testTemporariesAndConstructors1F() { |
| Status s1 = doSomething(); // Test the copy constructor. |
| Status s2 = s1; |
| } // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}} |
| |
| void testTemporariesAndConstructors1S() { |
| Status s1 = doSomething(); // Test the copy constructor. |
| Status s2(s1); |
| s2.check(); |
| } |
| |
| void testTemporariesAndConstructors2F() { |
| // Test the move constructor. |
| Status s1 = doSomething(); |
| Status s2 = static_cast<Status&&>(s1); |
| } // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}} |
| |
| void testTemporariesAndConstructors2S() { |
| // Test the move constructor. |
| Status s1 = doSomething(); |
| Status s2 = static_cast<Status&&>(s1); |
| s2.check(); |
| } |
| |
| void testTemporariesAndOperators0F() { |
| // Test the assignment operator. |
| Status s1 = doSomething(); |
| Status s2; |
| s2 = s1; |
| } // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}} |
| |
| void testTemporariesAndOperators0S() { |
| // Test the assignment operator. |
| Status s1 = doSomething(); |
| Status s2; |
| s2 = s1; |
| s2.check(); |
| } |
| |
| void testTemporariesAndOperators1F() { |
| // Test the move assignment operator. |
| Status s1 = doSomething(); |
| Status s2; |
| s2 = static_cast<Status&&>(s1); |
| } // expected-warning {{invalid invocation of method '~Status' on object 's2' while it is in the 'unconsumed' state}} |
| |
| void testTemporariesAndOperators1S() { |
| // Test the move assignment operator. |
| Status s1 = doSomething(); |
| Status s2; |
| s2 = static_cast<Status&&>(s1); |
| s2.check(); |
| } |
| |
| void testTemporariesAndOperators2() { |
| Status s1 = doSomething(); |
| Status s2 = doSomething(); |
| s1 = s2; // expected-warning {{invalid invocation of method 'operator=' on object 's1' while it is in the 'unconsumed' state}} |
| s1.check(); |
| s2.check(); |
| } |
| |
| Status testReturnAutocast() { |
| Status s = doSomething(); |
| s.check(); // consume s |
| return s; // should autocast back to unconsumed |
| } |
| |
| |
| namespace TestParens { |
| |
| void test3() { |
| checkStat((doSomething())); |
| } |
| |
| void test4() { |
| Status s = (doSomething()); |
| s.check(); |
| } |
| |
| void test5() { |
| (doSomething()).check(); |
| } |
| |
| void test6() { |
| if ((doSomething()) == Status::OK) |
| return; |
| } |
| |
| } // end namespace TestParens |
| |
| } // end namespace InitializerAssertionFailTest |
| |
| |
| namespace std { |
| void move(); |
| template<class T> |
| void move(T&&); |
| |
| namespace __1 { |
| void move(); |
| template<class T> |
| void move(T&&); |
| } |
| } |
| |
| namespace PR18260 { |
| class X { |
| public: |
| void move(); |
| } x; |
| |
| void test() { |
| x.move(); |
| std::move(); |
| std::move(x); |
| std::__1::move(); |
| std::__1::move(x); |
| } |
| } // end namespace PR18260 |
| |