]> granicus.if.org Git - clang/commitdiff
Merging r214050:
authorBill Wendling <isanbard@gmail.com>
Mon, 4 Aug 2014 18:19:14 +0000 (18:19 +0000)
committerBill Wendling <isanbard@gmail.com>
Mon, 4 Aug 2014 18:19:14 +0000 (18:19 +0000)
------------------------------------------------------------------------
r214050 | rsmith | 2014-07-26 22:12:49 -0700 (Sat, 26 Jul 2014) | 7 lines

When looking for temporary dtors while building the CFG, do not walk into
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!

------------------------------------------------------------------------

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

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

index d883a32e0ef004f9f5873a2cecdb76f63290390e..3a43d6dac1408494f61eeaf7d70eda33fa113b8f 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 d6361e8767c7a9941afbcfeb30a9d4db5b30dcd4..842a385fbcdb6342d374ef657e50af0d4105dfc6 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 16bb86cc219cab73dd10be6ad3c24a4f7bfc0efe..531dc23995d27360a83e4d392dca8cf4eef701b2 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