From: Nicholas Allegra Date: Thu, 19 Sep 2019 23:00:31 +0000 (+0000) Subject: [Consumed] Treat by-value class arguments as consuming by default, like rvalue refs. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ac5593526c588430a8fc6ff95ae1489a3c8f329b;p=clang [Consumed] Treat by-value class arguments as consuming by default, like rvalue refs. Differential Revision: https://reviews.llvm.org/D67743 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@372361 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp index 17bc29ba88..cde753e8ec 100644 --- a/lib/Analysis/Consumed.cpp +++ b/lib/Analysis/Consumed.cpp @@ -644,10 +644,10 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg, continue; // Adjust state on the caller side. - if (isRValueRef(ParamType)) - setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed); - else if (ReturnTypestateAttr *RT = Param->getAttr()) + if (ReturnTypestateAttr *RT = Param->getAttr()) setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT)); + else if (isRValueRef(ParamType) || isConsumableType(ParamType)) + setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed); else if (isPointerOrRef(ParamType) && (!ParamType->getPointeeType().isConstQualified() || isSetOnReadPtrType(ParamType))) diff --git a/test/SemaCXX/warn-consumed-analysis.cpp b/test/SemaCXX/warn-consumed-analysis.cpp index 0a6aed6186..b4dddb6763 100644 --- a/test/SemaCXX/warn-consumed-analysis.cpp +++ b/test/SemaCXX/warn-consumed-analysis.cpp @@ -53,12 +53,18 @@ 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 var); void baf1(const ConsumableClass &var); void baf2(const ConsumableClass *var); @@ -120,6 +126,19 @@ void testDestruction() { 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(); // expected-warning {{invalid invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}} } @@ -413,10 +432,15 @@ void testParamReturnTypestateCallee(bool cond, ConsumableClass &Param RETUR Param.consume(); } +void testRvalueRefParamReturnTypestateCallee(ConsumableClass &&Param RETURN_TYPESTATE(unconsumed)) { + Param.unconsume(); +} + void testParamReturnTypestateCaller() { ConsumableClass var; testParamReturnTypestateCallee(true, var); + testRvalueRefParamReturnTypestateCallee((ConsumableClass &&)var); *var; } @@ -480,6 +504,9 @@ void testCallingConventions() { 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}}