From 627c7f9740dfe9c208543798eccbe5ca23e1ef42 Mon Sep 17 00:00:00 2001 From: DeLesley Hutchins Date: Fri, 11 Oct 2013 21:55:33 +0000 Subject: [PATCH] Consumed analysis: check destructor calls. This allows the callable_when attribute to be attached to destructors. Original patch by chris.wailes@gmail.com, reviewed and edited by delesley. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192508 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/Consumed.cpp | 75 ++++++++++++++++++------- test/SemaCXX/warn-consumed-analysis.cpp | 22 +++++++- 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp index d291f627d0..85dd821892 100644 --- a/lib/Analysis/Consumed.cpp +++ b/lib/Analysis/Consumed.cpp @@ -51,14 +51,14 @@ using namespace consumed; // Key method definition ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {} -static SourceLocation getWarningLocForLoopExit(const CFGBlock *ExitBlock) { +static SourceLocation getLastStmtLoc(const CFGBlock *Block) { // Find the source location of the last statement in the block, if the block // is not empty. - if (const Stmt *StmtNode = ExitBlock->getTerminator()) { + if (const Stmt *StmtNode = Block->getTerminator()) { return StmtNode->getLocStart(); } else { - for (CFGBlock::const_reverse_iterator BI = ExitBlock->rbegin(), - BE = ExitBlock->rend(); BI != BE; ++BI) { + for (CFGBlock::const_reverse_iterator BI = Block->rbegin(), + BE = Block->rend(); BI != BE; ++BI) { // FIXME: Handle other CFGElement kinds. if (Optional CS = BI->getAs()) return CS->getStmt()->getLocStart(); @@ -66,10 +66,10 @@ static SourceLocation getWarningLocForLoopExit(const CFGBlock *ExitBlock) { } // The block is empty, and has a single predecessor. Use its exit location. - assert(ExitBlock->pred_size() == 1 && *ExitBlock->pred_begin() && - ExitBlock->succ_size() != 0); + assert(Block->pred_size() == 1 && *Block->pred_begin() && + Block->succ_size() != 0); - return getWarningLocForLoopExit(*ExitBlock->pred_begin()); + return getLastStmtLoc(*Block->pred_begin()); } static ConsumedState invertConsumedUnconsumed(ConsumedState State) { @@ -340,10 +340,6 @@ class ConsumedStmtVisitor : public ConstStmtVisitor { ConsumedAnalyzer &Analyzer; ConsumedStateMap *StateMap; MapType PropagationMap; - - void checkCallability(const PropagationInfo &PInfo, - const FunctionDecl *FunDecl, - const CallExpr *Call); void forwardInfo(const Stmt *From, const Stmt *To); void handleTestingFunctionCall(const CallExpr *Call, const VarDecl *Var); bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl); @@ -351,12 +347,16 @@ class ConsumedStmtVisitor : public ConstStmtVisitor { QualType ReturnType); public: + void checkCallability(const PropagationInfo &PInfo, + const FunctionDecl *FunDecl, + SourceLocation BlameLoc); void Visit(const Stmt *StmtNode); void VisitBinaryOperator(const BinaryOperator *BinOp); void VisitCallExpr(const CallExpr *Call); void VisitCastExpr(const CastExpr *Cast); + void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp); void VisitCXXConstructExpr(const CXXConstructExpr *Call); void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call); void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call); @@ -389,7 +389,7 @@ public: void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, const FunctionDecl *FunDecl, - const CallExpr *Call) { + SourceLocation BlameLoc) { if (!FunDecl->hasAttr()) return; @@ -407,7 +407,7 @@ void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, Analyzer.WarningsHandler.warnUseInInvalidState( FunDecl->getNameAsString(), Var->getNameAsString(), - stateToString(VarState), Call->getExprLoc()); + stateToString(VarState), BlameLoc); } else if (PInfo.isState()) { @@ -417,8 +417,7 @@ void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, return; Analyzer.WarningsHandler.warnUseOfTempInInvalidState( - FunDecl->getNameAsString(), stateToString(PInfo.getState()), - Call->getExprLoc()); + FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc); } } @@ -581,6 +580,12 @@ void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) { forwardInfo(Cast->getSubExpr(), Cast); } +void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr( + const CXXBindTemporaryExpr *Temp) { + + forwardInfo(Temp->getSubExpr(), Temp); +} + void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) { CXXConstructorDecl *Constructor = Call->getConstructor(); @@ -622,6 +627,7 @@ void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) { } } + void ConsumedStmtVisitor::VisitCXXMemberCallExpr( const CXXMemberCallExpr *Call) { @@ -633,7 +639,7 @@ void ConsumedStmtVisitor::VisitCXXMemberCallExpr( PropagationInfo PInfo = Entry->second; const CXXMethodDecl *MethodDecl = Call->getMethodDecl(); - checkCallability(PInfo, MethodDecl, Call); + checkCallability(PInfo, MethodDecl, Call->getExprLoc()); if (PInfo.isVar()) { if (isTestingFunction(MethodDecl)) @@ -721,7 +727,7 @@ void ConsumedStmtVisitor::VisitCXXOperatorCallExpr( if (Entry != PropagationMap.end()) { PropagationInfo PInfo = Entry->second; - checkCallability(PInfo, FunDecl, Call); + checkCallability(PInfo, FunDecl, Call->getExprLoc()); if (PInfo.isVar()) { if (isTestingFunction(FunDecl)) @@ -1052,7 +1058,7 @@ void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead, ConsumedWarningsHandlerBase &WarningsHandler) { ConsumedState LocalState; - SourceLocation BlameLoc = getWarningLocForLoopExit(LoopBack); + SourceLocation BlameLoc = getLastStmtLoc(LoopBack); for (MapType::const_iterator DMI = LoopBackStates->Map.begin(), DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) { @@ -1266,8 +1272,37 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { case CFGElement::Statement: Visitor.Visit(BI->castAs().getStmt()); break; - case CFGElement::AutomaticObjectDtor: - CurrStates->remove(BI->castAs().getVarDecl()); + + case CFGElement::TemporaryDtor: { + const CFGTemporaryDtor DTor = BI->castAs(); + const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr(); + PropagationInfo PInfo = Visitor.getInfo(BTE); + + if (PInfo.isValid()) + Visitor.checkCallability(PInfo, + DTor.getDestructorDecl(AC.getASTContext()), + BTE->getExprLoc()); + break; + } + + case CFGElement::AutomaticObjectDtor: { + const CFGAutomaticObjDtor DTor = BI->castAs(); + + const VarDecl *Var = DTor.getVarDecl(); + ConsumedState VarState = CurrStates->getState(Var); + + if (VarState != CS_None) { + PropagationInfo PInfo(Var); + + Visitor.checkCallability(PInfo, + DTor.getDestructorDecl(AC.getASTContext()), + getLastStmtLoc(CurrBlock)); + + CurrStates->remove(Var); + } + break; + } + default: break; } diff --git a/test/SemaCXX/warn-consumed-analysis.cpp b/test/SemaCXX/warn-consumed-analysis.cpp index 0618f77b5f..28b7794789 100644 --- a/test/SemaCXX/warn-consumed-analysis.cpp +++ b/test/SemaCXX/warn-consumed-analysis.cpp @@ -14,7 +14,7 @@ template class CONSUMABLE(unconsumed) ConsumableClass { T var; - public: +public: ConsumableClass(); ConsumableClass(nullptr_t p) RETURN_TYPESTATE(consumed); ConsumableClass(T val) RETURN_TYPESTATE(unconsumed); @@ -46,6 +46,15 @@ class CONSUMABLE(unconsumed) ConsumableClass { void consume() CONSUMES; }; +class CONSUMABLE(unconsumed) DestructorTester { +public: + DestructorTester(int); + + void operator*(); + + ~DestructorTester() CALLABLE_WHEN("consumed"); +}; + void baf0(const ConsumableClass var); void baf1(const ConsumableClass &var); void baf2(const ConsumableClass *var); @@ -83,6 +92,17 @@ void testInitialization() { } } +void testDestruction() { + DestructorTester D0(42), D1(42); + + *D0; + *D1; + + 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}} +} + void testTempValue() { *ConsumableClass(); // expected-warning {{invalid invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}} } -- 2.40.0