From 4137af286f7f547ee81349da5130e4b155232531 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 27 Jul 2014 05:12:49 +0000 Subject: [PATCH] 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! llvm-svn: 214050 --- clang/include/clang/AST/ExprCXX.h | 6 ++++++ clang/lib/Analysis/CFG.cpp | 27 ++++++++++++++++++++++++++- clang/test/SemaCXX/return-noreturn.cpp | 22 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index d883a32..3a43d6d 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -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_inits() const { + return llvm::iterator_range(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 { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index d6361e8..842a385 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -3495,10 +3495,35 @@ tryAgain: case Stmt::ParenExprClass: E = cast(E)->getSubExpr(); goto tryAgain; - + case Stmt::MaterializeTemporaryExprClass: E = cast(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(E); + CFGBlock *B = Block; + for (Expr *Init : LE->capture_inits()) { + if (CFGBlock *R = VisitForTemporaryDtors(Init)) + B = R; + } + return B; + } + + case Stmt::CXXDefaultArgExprClass: + E = cast(E)->getExpr(); + goto tryAgain; + + case Stmt::CXXDefaultInitExprClass: + E = cast(E)->getExpr(); + goto tryAgain; } } diff --git a/clang/test/SemaCXX/return-noreturn.cpp b/clang/test/SemaCXX/return-noreturn.cpp index 16bb86c..531dc23 100644 --- a/clang/test/SemaCXX/return-noreturn.cpp +++ b/clang/test/SemaCXX/return-noreturn.cpp @@ -146,3 +146,25 @@ void PR9412_f() { PR9412_t(); // expected-note {{in instantiation of function template specialization 'PR9412_t<0>' requested here}} } +#if __cplusplus >= 201103L +namespace LambdaVsTemporaryDtor { + struct Y { ~Y(); }; + struct X { template 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 -- 2.7.4