diff options
-rw-r--r-- | clang/lib/Analysis/Consumed.cpp | 28 | ||||
-rw-r--r-- | clang/test/SemaCXX/warn-consumed-analysis.cpp | 50 |
2 files changed, 52 insertions, 26 deletions
diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp index ed22bda16aa..cb6f31f0bf6 100644 --- a/clang/lib/Analysis/Consumed.cpp +++ b/clang/lib/Analysis/Consumed.cpp @@ -183,11 +183,8 @@ static bool isKnownState(ConsumedState State) { llvm_unreachable("invalid enum"); } -static bool isRValueRefish(QualType ParamType) { - return ParamType->isRValueReferenceType(); /* || - (ParamType->isLValueReferenceType() && - !cast<LValueReferenceType>( - ParamType.getCanonicalType())->isSpelledAsLValue()); */ +static bool isRValueRef(QualType ParamType) { + return ParamType->isRValueReferenceType(); } static bool isTestingFunction(const FunctionDecl *FunDecl) { @@ -607,8 +604,8 @@ void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg, const FunctionDecl *FunD) { unsigned Offset = 0; - if (isa<CXXMethodDecl>(FunD)) - Offset = 1; // First argument to call is 'this' parameter + if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD)) + Offset = 1; // first argument is 'this' // check explicit parameters for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) { @@ -640,15 +637,14 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg, continue; // Adjust state on the caller side. - if (isRValueRefish(ParamType)) + if (isRValueRef(ParamType)) setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed); else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>()) setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT)); - else if (isPointerOrRef(ParamType)) { - if (!ParamType->getPointeeType().isConstQualified() || - isSetOnReadPtrType(ParamType)) - setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown); - } + else if (isPointerOrRef(ParamType) && + (!ParamType->getPointeeType().isConstQualified() || + isSetOnReadPtrType(ParamType))) + setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown); } if (!ObjArg) @@ -885,11 +881,11 @@ void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { ParamState = mapParamTypestateAttrState(PTA); else if (isConsumableType(ParamType)) ParamState = mapConsumableAttrState(ParamType); - else if (isRValueRefish(ParamType) && - isConsumableType(ParamType->getPointeeType())) + else if (isRValueRef(ParamType) && + isConsumableType(ParamType->getPointeeType())) ParamState = mapConsumableAttrState(ParamType->getPointeeType()); else if (ParamType->isReferenceType() && - isConsumableType(ParamType->getPointeeType())) + isConsumableType(ParamType->getPointeeType())) ParamState = consumed::CS_Unknown; if (ParamState != CS_None) diff --git a/clang/test/SemaCXX/warn-consumed-analysis.cpp b/clang/test/SemaCXX/warn-consumed-analysis.cpp index 76f4f8d8111..3923f694395 100644 --- a/clang/test/SemaCXX/warn-consumed-analysis.cpp +++ b/clang/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; } |