aboutsummaryrefslogtreecommitdiff
path: root/test/SemaCXX/warn-consumed-analysis.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/SemaCXX/warn-consumed-analysis.cpp')
-rw-r--r--test/SemaCXX/warn-consumed-analysis.cpp176
1 files changed, 147 insertions, 29 deletions
diff --git a/test/SemaCXX/warn-consumed-analysis.cpp b/test/SemaCXX/warn-consumed-analysis.cpp
index 2c372c752baf..977b862a92b5 100644
--- a/test/SemaCXX/warn-consumed-analysis.cpp
+++ b/test/SemaCXX/warn-consumed-analysis.cpp
@@ -51,7 +51,7 @@ public:
class CONSUMABLE(unconsumed) DestructorTester {
public:
- DestructorTester() RETURN_TYPESTATE(unconsumed);
+ DestructorTester();
DestructorTester(int);
void operator*() CALLABLE_WHEN("unconsumed");
@@ -82,11 +82,21 @@ ConsumableClass<int> returnsUnknown() RETURN_TYPESTATE(unknown);
void testInitialization() {
ConsumableClass<int> var0;
ConsumableClass<int> var1 = ConsumableClass<int>();
-
- var0 = 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;
@@ -98,19 +108,16 @@ void testInitialization() {
}
void testDestruction() {
- DestructorTester D0(42), D1(42);
+ DestructorTester D0(42), D1(42), D2;
*D0;
*D1;
-
- DestructorTester D2;
- *D2;
+ *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}} \
- expected-warning {{invalid invocation of method '~DestructorTester' on object 'D2' 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 testTempValue() {
@@ -427,6 +434,29 @@ void testParamTypestateCaller() {
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;
}
@@ -645,12 +675,17 @@ void read(bool sf) {
} // end namespace ContinueICETest
-namespace InitializerAssertionFailTest {
+namespace StatusUseCaseTests {
-class CONSUMABLE(unconsumed) Status {
+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);
@@ -660,6 +695,8 @@ public:
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; }
@@ -667,13 +704,22 @@ public:
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 handleStatusPtr(const Status* s);
+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}}
@@ -691,6 +737,19 @@ 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();
@@ -702,8 +761,17 @@ void testSimpleTemporaries5() {
}
void testSimpleTemporaries6() {
- Status s = doSomething();
- handleStatus(s);
+ Status s1 = doSomething();
+ handleStatus(s1);
+
+ Status s2 = doSomething();
+ handleStatusRef(s2);
+
+ Status s3 = doSomething();
+ handleStatusPtr(&s3);
+
+ Status s4 = doSomething();
+ handleStatusUnmarked(s4);
}
void testSimpleTemporaries7() {
@@ -745,38 +813,58 @@ void testTemporariesWithConditionals3() {
}
void testTemporariesAndConstructors0() {
- Status s(doSomething());
+ Status s(doSomething()); // Test the copy constructor.
s.check();
}
-void testTemporariesAndConstructors1() {
- // Test the copy constructor.
-
- Status s1 = doSomething();
+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();
-} // expected-warning {{invalid invocation of method '~Status' on object 's1' while it is in the 'unconsumed' state}}
+}
-void testTemporariesAndConstructors2() {
+void testTemporariesAndConstructors2F() {
// Test the move constructor.
-
Status s1 = doSomething();
- Status s2(static_cast<Status&&>(s1));
+ 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 testTemporariesAndOperators0() {
+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();
-} // expected-warning {{invalid invocation of method '~Status' on object 's1' while it is in the 'unconsumed' state}}
+}
-void testTemporariesAndOperators1() {
+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);
@@ -791,6 +879,35 @@ void testTemporariesAndOperators2() {
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
@@ -820,3 +937,4 @@ namespace PR18260 {
std::__1::move(x);
}
} // end namespace PR18260
+