// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed-strict -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)) #define TEST_VAR(Var) Var.isValid() typedef decltype(nullptr) nullptr_t; template class CONSUMABLE(unconsumed) ConsumableClass { T var; public: ConsumableClass(); ConsumableClass(nullptr_t p) RETURN_TYPESTATE(consumed); ConsumableClass(T val); ConsumableClass(ConsumableClass &other); ConsumableClass(ConsumableClass &&other); 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(ConsumableClass &var); void baf1(ConsumableClass *var); void testIfStmt() { ConsumableClass var; if (var.isValid()) { // expected-warning {{unnecessary test. Variable 'var' is known to be in the 'consumed' state}} // Empty } else { // Empty } } void testComplexConditionals() { ConsumableClass var0, var1, var2; // Coerce all variables into the unknown state. baf0(var0); baf0(var1); baf0(var2); if (var0 && var1) { *var0; *var1; } else { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} } if (var0 || var1) { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} } 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; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}} } else { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} } if (var0 || !var1) { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} } else { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}} *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; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown 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; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} } if (!var0 || !var1) { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} } else { *var0; *var1; } if (!(var0 && var1)) { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown 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 an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} *var2; // expected-warning {{invocation of method 'operator*' on object 'var2' while it is in an unknown state}} } #if 0 // FIXME: Get this test to pass. if (var0 || var1 || var2) { *var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in an unknown state}} *var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in an unknown state}} *var2; // expected-warning {{invocation of method 'operator*' on object 'var2' while it is in an unknown state}} } 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 testCallingConventions() { ConsumableClass var(42); baf0(var); *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}} var = ConsumableClass(42); baf1(&var); *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}} } void testConstAndNonConstMemberFunctions() { ConsumableClass var(42); var.constCall(); *var; var.nonconstCall(); *var; } void testFunctionParam0(ConsumableClass ¶m) { *param; // expected-warning {{invocation of method 'operator*' on object 'param' while it is in an unknown state}} } void testNoWarnTestFromMacroExpansion() { ConsumableClass var(42); if (TEST_VAR(var)) { *var; } } void testSimpleForLoop() { ConsumableClass var; for (int i = 0; i < 10; ++i) { *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}} } *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}} } void testSimpleWhileLoop() { int i = 0; ConsumableClass var; while (i < 10) { *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}} ++i; } *var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in an unknown state}} }