r192508 - Consumed analysis: check destructor calls.
DeLesley Hutchins
delesley at google.com
Fri Oct 11 14:55:33 PDT 2013
Author: delesley
Date: Fri Oct 11 16:55:33 2013
New Revision: 192508
URL: http://llvm.org/viewvc/llvm-project?rev=192508&view=rev
Log:
Consumed analysis: check destructor calls.
This allows the callable_when attribute to be attached to destructors.
Original patch by chris.wailes at gmail.com, reviewed and edited by delesley.
Modified:
cfe/trunk/lib/Analysis/Consumed.cpp
cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp
Modified: cfe/trunk/lib/Analysis/Consumed.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/Consumed.cpp?rev=192508&r1=192507&r2=192508&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/Consumed.cpp (original)
+++ cfe/trunk/lib/Analysis/Consumed.cpp Fri Oct 11 16:55:33 2013
@@ -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<CFGStmt> CS = BI->getAs<CFGStmt>())
return CS->getStmt()->getLocStart();
@@ -66,10 +66,10 @@ static SourceLocation getWarningLocForLo
}
// 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 Const
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 Const
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<CallableWhenAttr>())
return;
@@ -407,7 +407,7 @@ void ConsumedStmtVisitor::checkCallabili
Analyzer.WarningsHandler.warnUseInInvalidState(
FunDecl->getNameAsString(), Var->getNameAsString(),
- stateToString(VarState), Call->getExprLoc());
+ stateToString(VarState), BlameLoc);
} else if (PInfo.isState()) {
@@ -417,8 +417,7 @@ void ConsumedStmtVisitor::checkCallabili
return;
Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
- FunDecl->getNameAsString(), stateToString(PInfo.getState()),
- Call->getExprLoc());
+ FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc);
}
}
@@ -581,6 +580,12 @@ void ConsumedStmtVisitor::VisitCastExpr(
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::VisitCXXConstr
}
}
+
void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
const CXXMemberCallExpr *Call) {
@@ -633,7 +639,7 @@ void ConsumedStmtVisitor::VisitCXXMember
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::VisitCXXOperat
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::intersectAtLoopHe
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(AnalysisDeclC
case CFGElement::Statement:
Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
break;
- case CFGElement::AutomaticObjectDtor:
- CurrStates->remove(BI->castAs<CFGAutomaticObjDtor>().getVarDecl());
+
+ case CFGElement::TemporaryDtor: {
+ const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
+ 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<CFGAutomaticObjDtor>();
+
+ 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;
}
Modified: cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp?rev=192508&r1=192507&r2=192508&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-consumed-analysis.cpp Fri Oct 11 16:55:33 2013
@@ -14,7 +14,7 @@ template <typename T>
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) ConsumableC
void consume() CONSUMES;
};
+class CONSUMABLE(unconsumed) DestructorTester {
+public:
+ DestructorTester(int);
+
+ void operator*();
+
+ ~DestructorTester() CALLABLE_WHEN("consumed");
+};
+
void baf0(const ConsumableClass<int> var);
void baf1(const ConsumableClass<int> &var);
void baf2(const ConsumableClass<int> *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<int>(); // expected-warning {{invalid invocation of method 'operator*' on a temporary object while it is in the 'consumed' state}}
}
More information about the cfe-commits
mailing list