When looking for temporary dtors while building the CFG, do not walk into
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 27 Jul 2014 05:12:49 +0000 (05:12 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 27 Jul 2014 05:12:49 +0000 (05:12 +0000)
lambda expressions (other than their capture initializers) nor blocks. Do walk
into default argument expressions and default initializer expressions.

These bugs were causing us to produce broken CFGs whenever a lambda expression
was used to initialize a libstdc++ std::function object!

llvm-svn: 214050

clang/include/clang/AST/ExprCXX.h
clang/lib/Analysis/CFG.cpp
clang/test/SemaCXX/return-noreturn.cpp

index d883a32..3a43d6d 100644 (file)
@@ -1479,6 +1479,12 @@ public:
   /// arguments.
   typedef Expr **capture_init_iterator;
 
+  /// \brief Retrieve the initialization expressions for this lambda's captures.
+  llvm::iterator_range<capture_init_iterator> capture_inits() const {
+    return llvm::iterator_range<capture_init_iterator>(capture_init_begin(),
+                                                       capture_init_end());
+  }
+
   /// \brief Retrieve the first initialization argument for this
   /// lambda expression (which initializes the first capture field).
   capture_init_iterator capture_init_begin() const {
index d6361e8..842a385 100644 (file)
@@ -3495,10 +3495,35 @@ tryAgain:
     case Stmt::ParenExprClass:
       E = cast<ParenExpr>(E)->getSubExpr();
       goto tryAgain;
-      
+
     case Stmt::MaterializeTemporaryExprClass:
       E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr();
       goto tryAgain;
+
+    case Stmt::BlockExprClass:
+      // Don't recurse into blocks; their subexpressions don't get evaluated
+      // here.
+      return Block;
+
+    case Stmt::LambdaExprClass: {
+      // For lambda expressions, only recurse into the capture initializers,
+      // and not the body.
+      auto *LE = cast<LambdaExpr>(E);
+      CFGBlock *B = Block;
+      for (Expr *Init : LE->capture_inits()) {
+        if (CFGBlock *R = VisitForTemporaryDtors(Init))
+          B = R;
+      }
+      return B;
+    }
+
+    case Stmt::CXXDefaultArgExprClass:
+      E = cast<CXXDefaultArgExpr>(E)->getExpr();
+      goto tryAgain;
+
+    case Stmt::CXXDefaultInitExprClass:
+      E = cast<CXXDefaultInitExpr>(E)->getExpr();
+      goto tryAgain;
   }
 }
 
index 16bb86c..531dc23 100644 (file)
@@ -146,3 +146,25 @@ void PR9412_f() {
     PR9412_t<PR9412_Exact>(); // expected-note {{in instantiation of function template specialization 'PR9412_t<0>' requested here}}
 }
 
+#if __cplusplus >= 201103L
+namespace LambdaVsTemporaryDtor {
+  struct Y { ~Y(); };
+  struct X { template<typename T> X(T, Y = Y()) {} };
+
+  struct Fatal { ~Fatal() __attribute__((noreturn)); };
+  struct FatalCopy { FatalCopy(); FatalCopy(const FatalCopy&, Fatal F = Fatal()); };
+
+  void foo();
+
+  int bar() {
+    X work([](){ Fatal(); });
+    foo();
+  } // expected-warning {{control reaches end of non-void function}}
+
+  int baz() {
+    FatalCopy fc;
+    X work([fc](){});
+    foo();
+  } // ok, initialization of lambda does not return
+}
+#endif