]> granicus.if.org Git - clang/commitdiff
Explicitly keep track of temporaries during the consumed analysis.
authorManuel Klimek <klimek@google.com>
Thu, 8 May 2014 11:50:00 +0000 (11:50 +0000)
committerManuel Klimek <klimek@google.com>
Thu, 8 May 2014 11:50:00 +0000 (11:50 +0000)
This makes the consumed analysis less dependent on the CFG layout and fixes
a bug where we wouldn't warn on an unconsumed value.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@208300 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/Analyses/Consumed.h
lib/Analysis/Consumed.cpp
test/SemaCXX/warn-consumed-analysis.cpp

index 3c9ba78548be87d83804fa1d724d0289aa5e239e..36e07c21907bf4c91084104bf0d4fa754e637c55 100644 (file)
@@ -185,8 +185,8 @@ namespace consumed {
     /// \brief Set the consumed state of a given temporary value.
     void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State);
     
-    /// \brief Remove the variable from our state map.
-    void remove(const VarDecl *Var);
+    /// \brief Remove the temporary value from our state map.
+    void remove(const CXXBindTemporaryExpr *Tmp);
     
     /// \brief Tests to see if there is a mismatch in the states stored in two
     /// maps.
index 6d590ab2e3d98e2ed3c907c820a131b5df8fe982..e3dcb92378618b7148f49c387c3996831530d5f9 100644 (file)
@@ -1233,8 +1233,8 @@ void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
   TmpMap[Tmp] = State;
 }
 
-void ConsumedStateMap::remove(const VarDecl *Var) {
-  VarMap.erase(Var);
+void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
+  TmpMap.erase(Tmp);
 }
 
 bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
@@ -1413,6 +1413,7 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
         Visitor.checkCallability(PropagationInfo(BTE),
                                  DTor.getDestructorDecl(AC.getASTContext()),
                                  BTE->getExprLoc());
+        CurrStates->remove(BTE);
         break;
       }
       
@@ -1432,8 +1433,6 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
       }
     }
     
-    CurrStates->clearTemporaries();
-    
     // TODO: Handle other forms of branching with precision, including while-
     //       and for-loops. (Deferred)
     if (!splitState(CurrBlock, Visitor)) {
index bd091c6f1ccf94b033731eead7efcc710bd814cd..977b862a92b5088f930c90478269583807fe669d 100644 (file)
@@ -704,6 +704,8 @@ public:
   void clear() CALLABLE_WHEN("unknown", "consumed") SET_TYPESTATE(consumed);
 
   ~Status() CALLABLE_WHEN("unknown", "consumed");
+
+  operator bool() const; // Will not consume the object.
 };
 
 
@@ -735,6 +737,10 @@ void testSimpleTemporaries3() {
   Status s = doSomething();
 }  // expected-warning {{invalid invocation of method '~Status' on object 's' while it is in the 'unconsumed' state}}
 
+void testTemporariesWithControlFlow(bool a) {
+  bool b = false || doSomething(); // expected-warning {{invalid invocation of method '~Status' on a temporary object while it is in the 'unconsumed' state}}
+}
+
 Status testSimpleTemporariesReturn0() {
   return doSomething();
 }