diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-01-30 22:05:38 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-01-30 22:05:38 +0000 |
commit | 40f08ebece6064c8aa705eca9cc32cd0e1534006 (patch) | |
tree | 81c741266759cd64155e3608eef8d0d95b073972 | |
parent | 0115b0879c617da4a222002fd7018417209457e5 (diff) | |
download | bcm5719-llvm-40f08ebece6064c8aa705eca9cc32cd0e1534006.tar.gz bcm5719-llvm-40f08ebece6064c8aa705eca9cc32cd0e1534006.zip |
Don't produce a 'returning reference to local' warning if a lambda returns a
reference (or pointer) to a variable from the closure object or from the
surrounding function scope.
llvm-svn: 200494
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 8 | ||||
-rw-r--r-- | clang/test/SemaCXX/return-stack-addr.cpp | 23 |
2 files changed, 28 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ee0e6702e0f..053ab2d620c 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -4136,6 +4136,10 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, case Stmt::DeclRefExprClass: { DeclRefExpr *DR = cast<DeclRefExpr>(E); + // If we leave the immediate function, the lifetime isn't about to end. + if (DR->refersToEnclosingLocal()) + return 0; + if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) // If this is a reference variable, follow through to the expression that // it points to. @@ -4292,6 +4296,10 @@ do { // local storage within the function, and if so, return the expression. DeclRefExpr *DR = cast<DeclRefExpr>(E); + // If we leave the immediate function, the lifetime isn't about to end. + if (DR->refersToEnclosingLocal()) + return 0; + if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { // Check if it refers to itself, e.g. "int& i = i;". if (V == ParentDecl) diff --git a/clang/test/SemaCXX/return-stack-addr.cpp b/clang/test/SemaCXX/return-stack-addr.cpp index fbbaf836f1a..7670798ecb9 100644 --- a/clang/test/SemaCXX/return-stack-addr.cpp +++ b/clang/test/SemaCXX/return-stack-addr.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s int* ret_local() { int x = 1; @@ -108,6 +108,11 @@ int* ret_cpp_const_cast(const int x) { return const_cast<int*>(&x); // expected-warning {{address of stack memory}} } +struct A { virtual ~A(); }; struct B : A {}; +A* ret_cpp_dynamic_cast(B b) { + return dynamic_cast<A*>(&b); // expected-warning {{address of stack memory}} +} + // PR 7999 - handle the case where a field is itself a reference. template <typename T> struct PR7999 { PR7999(T& t) : value(t) {} @@ -137,5 +142,17 @@ namespace PR8774 { } } -// TODO: test case for dynamic_cast. clang does not yet have -// support for C++ classes to write such a test case. +// Don't warn about returning a local variable from a surrounding function if +// we're within a lambda-expression. +void ret_from_lambda() { + int a; + int &b = a; + (void) [&]() -> int& { return a; }; + (void) [&]() -> int& { return b; }; + (void) [=]() mutable -> int& { return a; }; + (void) [=]() mutable -> int& { return b; }; + (void) [&]() -> int& { int a; return a; }; // expected-warning {{reference to stack}} + (void) [=]() -> int& { int a; return a; }; // expected-warning {{reference to stack}} + (void) [&]() -> int& { int &a = b; return a; }; + (void) [=]() mutable -> int& { int &a = b; return a; }; +} |