]> granicus.if.org Git - clang/commitdiff
Don't produce a 'returning reference to local' warning if a lambda returns a
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 30 Jan 2014 22:05:38 +0000 (22:05 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 30 Jan 2014 22:05:38 +0000 (22:05 +0000)
reference (or pointer) to a variable from the closure object or from the
surrounding function scope.

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

lib/Sema/SemaChecking.cpp
test/SemaCXX/return-stack-addr.cpp

index ee0e6702e0f341fa1007230fea7371e3b5f29b85..053ab2d620cd790d323a7b56d54b00b9a9f732a4 100644 (file)
@@ -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)
index fbbaf836f1abf6fb40ca0125f7e54ceb9d0fec27..7670798ecb9c13d623d502c9095297a35fbf9293 100644 (file)
@@ -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; };
+}