// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s #define CALLABLE_WHEN_UNCONSUMED __attribute__ ((callable_when_unconsumed)) #define CONSUMABLE __attribute__ ((consumable)) #define CONSUMES __attribute__ ((consumes)) #define RETURN_TYPESTATE(State) __attribute__ ((return_typestate(State))) #define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed)) typedef decltype(nullptr) nullptr_t; template class CONSUMABLE ConsumableClass { T var; public: ConsumableClass(); ConsumableClass(nullptr_t p) RETURN_TYPESTATE(consumed); ConsumableClass(T val) RETURN_TYPESTATE(unconsumed); ConsumableClass(ConsumableClass &other) RETURN_TYPESTATE(unconsumed); ConsumableClass(ConsumableClass &&other) RETURN_TYPESTATE(unconsumed); ConsumableClass& operator=(ConsumableClass &other); ConsumableClass& operator=(ConsumableClass &&other); ConsumableClass& operator=(nullptr_t) CONSUMES; template ConsumableClass& operator=(ConsumableClass &other); template ConsumableClass& operator=(ConsumableClass &&other); void operator()(int a) CONSUMES; void operator*() const CALLABLE_WHEN_UNCONSUMED; void unconsumedCall() const CALLABLE_WHEN_UNCONSUMED; bool isValid() const TESTS_UNCONSUMED; operator bool() const TESTS_UNCONSUMED; bool operator!=(nullptr_t) const TESTS_UNCONSUMED; void constCall() const; void nonconstCall(); void consume() CONSUMES; }; void baf0(const ConsumableClass var); void baf1(const ConsumableClass &var); void baf2(const ConsumableClass *var); void baf3(ConsumableClass &&var); ConsumableClass returnsUnconsumed() RETURN_TYPESTATE(unconsumed); ConsumableClass returnsUnconsumed() { return ConsumableClass(); // expected-warning {{return value not in expected state; expected 'unconsumed', observed 'consumed'}} } ConsumableClass returnsConsumed() RETURN_TYPESTATE(consumed); ConsumableClass returnsConsumed() { return ConsumableClass(); } void testInitialization() { ConsumableClass var0; ConsumableClass var1 = ConsumableClass(); var0 = ConsumableClass(); *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}} if (var0.isValid()) { *var0; *var1; } else { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} } } void testTempValue() { *ConsumableClass(); // expected-warning {{invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}} } void testSimpleRValueRefs() { ConsumableClass var0; ConsumableClass var1(42); *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; var0 = static_cast&&>(var1); *var0; *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } void testIfStmt() { ConsumableClass var; if (var.isValid()) { *var; } else { *var; // expected-warning {{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}} } else { *var; } if (var) { // Empty } else { *var; // expected-warning {{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}} } } void testComplexConditionals() { ConsumableClass var0, var1, var2; if (var0 && var1) { *var0; *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}} } if (var0 || var1) { *var0; *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}} } if (var0 && !var1) { *var0; *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}} } 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}} } else { *var0; *var1; } 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}} } else { *var0; *var1; } 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}} } else { *var0; *var1; } 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}} } else { *var0; *var1; } 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}} } else { *var0; *var1; } if (var0 && var1 && var2) { *var0; *var1; *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}} } #if 0 // FIXME: Get this test to pass. if (var0 || var1 || var2) { *var0; *var1; *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}} } #endif } void testStateChangeInBranch() { ConsumableClass var; // Make var enter the 'unknown' state. baf1(var); if (!var) { var = ConsumableClass(42); } *var; } void testFunctionParam(ConsumableClass param) { if (param.isValid()) { *param; } else { *param; // expected-warning {{invocation of method 'operator*' on object 'param' while it is in the 'consumed' state}} } param = nullptr; *param; // expected-warning {{invocation of method 'operator*' on object 'param' while it is in the 'consumed' state}} } void testCallingConventions() { ConsumableClass var(42); baf0(var); *var; baf1(var); *var; baf2(&var); *var; baf3(static_cast&&>(var)); *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testReturnStates() { ConsumableClass var; var = returnsUnconsumed(); *var; var = returnsConsumed(); *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testMoveAsignmentish() { ConsumableClass var0; ConsumableClass var1(42); *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *var1; var0 = static_cast&&>(var1); *var0; *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} var1 = ConsumableClass(42); var1 = nullptr; *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } void testConditionalMerge() { ConsumableClass var; if (var.isValid()) { // Empty } *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} if (var.isValid()) { // Empty } else { // Empty } *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConsumes0() { ConsumableClass var(42); *var; var.consume(); *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConsumes1() { ConsumableClass var(nullptr); *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } void testConsumes2() { ConsumableClass var(42); var.unconsumedCall(); var(6); var.unconsumedCall(); // expected-warning {{invocation of method 'unconsumedCall' on object 'var' while it is in the 'consumed' state}} } void testNonsenseState() { ConsumableClass var(42); if (var) { *var; } else { *var; } *var; } void testSimpleForLoop() { ConsumableClass var; for (int i = 0; i < 10; ++i) { *var; } *var; } void testSimpleWhileLoop() { int i = 0; ConsumableClass var; while (i < 10) { *var; ++i; } *var; }