2013-08-13 05:20:55 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -verify -Wconsumed -std=c++11 %s
|
|
|
|
|
|
|
|
#define CALLABLE_WHEN_UNCONSUMED __attribute__ ((callable_when_unconsumed))
|
|
|
|
#define CONSUMES __attribute__ ((consumes))
|
|
|
|
#define TESTS_UNCONSUMED __attribute__ ((tests_unconsumed))
|
|
|
|
|
|
|
|
typedef decltype(nullptr) nullptr_t;
|
|
|
|
|
|
|
|
template <typename T>
|
2013-08-24 02:40:39 +08:00
|
|
|
class ConsumableClass {
|
2013-08-13 05:20:55 +08:00
|
|
|
T var;
|
|
|
|
|
|
|
|
public:
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass(void);
|
|
|
|
ConsumableClass(nullptr_t p) CONSUMES;
|
|
|
|
ConsumableClass(T val);
|
|
|
|
ConsumableClass(ConsumableClass<T> &other);
|
|
|
|
ConsumableClass(ConsumableClass<T> &&other);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<T>& operator=(ConsumableClass<T> &other);
|
|
|
|
ConsumableClass<T>& operator=(ConsumableClass<T> &&other);
|
|
|
|
ConsumableClass<T>& operator=(nullptr_t);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
template <typename U>
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<T>& operator=(ConsumableClass<U> &other);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
template <typename U>
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<T>& operator=(ConsumableClass<U> &&other);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
2013-08-23 04:44:47 +08:00
|
|
|
void operator()(int a) CONSUMES;
|
2013-08-13 05:20:55 +08:00
|
|
|
void operator*(void) const CALLABLE_WHEN_UNCONSUMED;
|
2013-08-23 04:44:47 +08:00
|
|
|
void unconsumedCall(void) const CALLABLE_WHEN_UNCONSUMED;
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
bool isValid(void) const TESTS_UNCONSUMED;
|
|
|
|
operator bool() const TESTS_UNCONSUMED;
|
2013-08-23 04:44:47 +08:00
|
|
|
bool operator!=(nullptr_t) const TESTS_UNCONSUMED;
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
void constCall(void) const;
|
|
|
|
void nonconstCall(void);
|
|
|
|
|
|
|
|
void consume(void) CONSUMES;
|
|
|
|
};
|
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
void baf0(const ConsumableClass<int> var);
|
|
|
|
void baf1(const ConsumableClass<int> &var);
|
|
|
|
void baf2(const ConsumableClass<int> *var);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
void baf3(ConsumableClass<int> &&var);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
void testInitialization(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var0;
|
|
|
|
ConsumableClass<int> var1 = ConsumableClass<int>();
|
2013-08-13 05:20:55 +08:00
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
var0 = ConsumableClass<int>();
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
*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; // 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 the 'consumed' state}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
void testTempValue() {
|
|
|
|
*ConsumableClass<int>(); // expected-warning {{invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}}
|
2013-08-23 04:44:47 +08:00
|
|
|
}
|
|
|
|
|
2013-08-13 05:20:55 +08:00
|
|
|
void testSimpleRValueRefs(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var0;
|
|
|
|
ConsumableClass<int> var1(42);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
*var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
|
|
|
|
*var1;
|
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
var0 = static_cast<ConsumableClass<int>&&>(var1);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
*var0;
|
|
|
|
*var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testIfStmt(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var;
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
if (var.isValid()) {
|
|
|
|
// Empty
|
|
|
|
|
|
|
|
} 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}}
|
|
|
|
}
|
2013-08-23 04:44:47 +08:00
|
|
|
|
|
|
|
if (var != nullptr) {
|
|
|
|
// Empty
|
|
|
|
|
|
|
|
} else {
|
|
|
|
*var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
|
|
|
|
}
|
2013-08-13 05:20:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void testCallingConventions(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var(42);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
baf0(var);
|
|
|
|
*var;
|
|
|
|
|
|
|
|
baf1(var);
|
|
|
|
*var;
|
|
|
|
|
|
|
|
baf2(&var);
|
|
|
|
*var;
|
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
baf3(static_cast<ConsumableClass<int>&&>(var));
|
2013-08-13 05:20:55 +08:00
|
|
|
*var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testMoveAsignmentish(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var0;
|
|
|
|
ConsumableClass<long> var1(42);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
*var0; // expected-warning {{invocation of method 'operator*' on object 'var0' while it is in the 'consumed' state}}
|
|
|
|
*var1;
|
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
var0 = static_cast<ConsumableClass<long>&&>(var1);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
*var0;
|
|
|
|
*var1; // expected-warning {{invocation of method 'operator*' on object 'var1' while it is in the 'consumed' state}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testConditionalMerge(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var;
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
if (var.isValid()) {
|
|
|
|
// Empty
|
|
|
|
}
|
|
|
|
|
|
|
|
*var;
|
|
|
|
|
|
|
|
if (var.isValid()) {
|
|
|
|
// Empty
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Empty
|
|
|
|
}
|
|
|
|
|
|
|
|
*var;
|
|
|
|
}
|
|
|
|
|
|
|
|
void testConsumes0(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var(42);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
*var;
|
|
|
|
|
|
|
|
var.consume();
|
|
|
|
|
|
|
|
*var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testConsumes1(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var(nullptr);
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
*var; // expected-warning {{invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}}
|
|
|
|
}
|
|
|
|
|
2013-08-23 04:44:47 +08:00
|
|
|
void testConsumes2(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var(42);
|
2013-08-23 04:44:47 +08:00
|
|
|
|
|
|
|
var.unconsumedCall();
|
|
|
|
var(6);
|
|
|
|
|
|
|
|
var.unconsumedCall(); // expected-warning {{invocation of method 'unconsumedCall' on object 'var' while it is in the 'consumed' state}}
|
|
|
|
}
|
|
|
|
|
2013-08-13 05:20:55 +08:00
|
|
|
void testSimpleForLoop(void) {
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var;
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < 10; ++i) {
|
|
|
|
*var;
|
|
|
|
}
|
|
|
|
|
|
|
|
*var;
|
|
|
|
}
|
|
|
|
|
|
|
|
void testSimpleWhileLoop(void) {
|
|
|
|
int i = 0;
|
|
|
|
|
2013-08-24 02:40:39 +08:00
|
|
|
ConsumableClass<int> var;
|
2013-08-13 05:20:55 +08:00
|
|
|
|
|
|
|
while (i < 10) {
|
|
|
|
*var;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
*var;
|
|
|
|
}
|