From be63ab6612b250972ae528ae910e5fa64f9c5731 Mon Sep 17 00:00:00 2001 From: DeLesley Hutchins Date: Fri, 18 Oct 2013 19:25:18 +0000 Subject: [PATCH] Consumed analysis: assume that non-const reference parameters are initially in the "uknown" state. Patch by chris.wailes@gmail.com. Reviewed by delesley. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192995 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/Consumed.cpp | 34 +++++++++++++++--------- test/SemaCXX/warn-consumed-analysis.cpp | 35 +++++++++++++++++-------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp index ef9617a3ec..8358b6b4e1 100644 --- a/lib/Analysis/Consumed.cpp +++ b/lib/Analysis/Consumed.cpp @@ -159,10 +159,20 @@ static bool isKnownState(ConsumedState State) { llvm_unreachable("invalid enum"); } +static bool isRValueRefish(QualType ParamType) { + return ParamType->isRValueReferenceType() || + (ParamType->isLValueReferenceType() && + !cast(*ParamType).isSpelledAsLValue()); +} + static bool isTestingFunction(const FunctionDecl *FunDecl) { return FunDecl->hasAttr(); } +static bool isValueType(QualType ParamType) { + return !(ParamType->isPointerType() || ParamType->isReferenceType()); +} + static ConsumedState mapConsumableAttrState(const QualType QT) { assert(isConsumableType(QT)); @@ -617,20 +627,15 @@ void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { // Adjust state on the caller side. - if (ParamType->isRValueReferenceType() || - (ParamType->isLValueReferenceType() && - !cast(*ParamType).isSpelledAsLValue())) { - + if (isRValueRefish(ParamType)) { StateMap->setState(PInfo.getVar(), consumed::CS_Consumed); } else if (Param->hasAttr()) { StateMap->setState(PInfo.getVar(), mapReturnTypestateAttrState(Param->getAttr())); - } else if (!(ParamType.isConstQualified() || - ((ParamType->isReferenceType() || - ParamType->isPointerType()) && - ParamType->getPointeeType().isConstQualified()))) { + } else if (!isValueType(ParamType) && + !ParamType->getPointeeType().isConstQualified()) { StateMap->setState(PInfo.getVar(), consumed::CS_Unknown); } @@ -856,14 +861,17 @@ void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { ConsumedState ParamState = consumed::CS_None; if (Param->hasAttr()) { - ParamState = - mapParamTypestateAttrState(Param->getAttr()); - - } else if (!(ParamType->isPointerType() || ParamType->isReferenceType()) && - isConsumableType(ParamType)) { + const ParamTypestateAttr *PTAttr = Param->getAttr(); + ParamState = mapParamTypestateAttrState(PTAttr); + } else if (isValueType(ParamType) && isConsumableType(ParamType)) { ParamState = mapConsumableAttrState(ParamType); + } else if (isRValueRefish(ParamType) && + isConsumableType(ParamType->getPointeeType())) { + + ParamState = mapConsumableAttrState(ParamType->getPointeeType()); + } else if (ParamType->isReferenceType() && isConsumableType(ParamType->getPointeeType())) { ParamState = consumed::CS_Unknown; diff --git a/test/SemaCXX/warn-consumed-analysis.cpp b/test/SemaCXX/warn-consumed-analysis.cpp index b84c69c453..14deae58f9 100644 --- a/test/SemaCXX/warn-consumed-analysis.cpp +++ b/test/SemaCXX/warn-consumed-analysis.cpp @@ -63,9 +63,10 @@ void baf0(const ConsumableClass var); void baf1(const ConsumableClass &var); void baf2(const ConsumableClass *var); -void baf3(ConsumableClass &var); -void baf4(ConsumableClass *var); -void baf5(ConsumableClass &&var); +void baf3(ConsumableClass var); +void baf4(ConsumableClass &var); +void baf5(ConsumableClass *var); +void baf6(ConsumableClass &&var); ConsumableClass returnsUnconsumed() { return ConsumableClass(); // expected-warning {{return value not in expected state; expected 'unconsumed', observed 'consumed'}} @@ -268,9 +269,9 @@ void testComplexConditionals1() { ConsumableClass var0, var1, var2; // Coerce all variables into the unknown state. - baf3(var0); - baf3(var1); - baf3(var2); + baf4(var0); + baf4(var1); + baf4(var2); if (var0 && var1) { *var0; @@ -374,7 +375,7 @@ void testStateChangeInBranch() { ConsumableClass var; // Make var enter the 'unknown' state. - baf3(var); + baf4(var); if (!var) { var = ConsumableClass(42); @@ -426,6 +427,18 @@ void testParamTypestateCaller() { testParamTypestateCallee(Var0, Var1); // expected-warning {{argument not in expected state; expected 'consumed', observed 'unconsumed'}} } +void baf3(ConsumableClass var) { + *var; +} + +void baf4(ConsumableClass &var) { + *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} +} + +void baf6(ConsumableClass &&var) { + *var; +} + void testCallingConventions() { ConsumableClass var(42); @@ -438,15 +451,15 @@ void testCallingConventions() { baf2(&var); *var; - baf3(var); + baf4(var); *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} var = ConsumableClass(42); - baf4(&var); + baf5(&var); *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'unknown' state}} var = ConsumableClass(42); - baf5(static_cast&&>(var)); + baf6(static_cast&&>(var)); *var; // expected-warning {{invalid invocation of method 'operator*' on object 'var' while it is in the 'consumed' state}} } @@ -483,7 +496,7 @@ void testCallableWhen() { *var; - baf3(var); + baf4(var); var.callableWhenUnknown(); } -- 2.40.0