]> granicus.if.org Git - clang/commitdiff
Fix two false positives in -Wreturn-stack-address
authorRichard Trieu <rtrieu@google.com>
Fri, 5 Aug 2016 23:24:47 +0000 (23:24 +0000)
committerRichard Trieu <rtrieu@google.com>
Fri, 5 Aug 2016 23:24:47 +0000 (23:24 +0000)
If the return type is a pointer and the function returns the reference to a
pointer, don't warn since only the value is returned, not the reference.

If a reference function parameter appears in the reference chain, don't warn
since binding happens at the caller scope, so addresses returned are not
to local stack.  This includes default arguments as well.

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

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

index 2ca3d12edb7730daa8c0ba1d407d6109ad4ce584..fd90121bfe34b511724e15df8b4d3af978f2bc4c 100644 (file)
@@ -6572,6 +6572,12 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
   if (!stackE)
     return; // Nothing suspicious was found.
 
+  // Parameters are initalized in the calling scope, so taking the address
+  // of a parameter reference doesn't need a warning.
+  for (auto *DRE : refVars)
+    if (isa<ParmVarDecl>(DRE->getDecl()))
+      return;
+
   SourceLocation diagLoc;
   SourceRange diagRange;
   if (refVars.empty()) {
@@ -6595,6 +6601,13 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
   } else if (isa<AddrLabelExpr>(stackE)) { // address of label.
     S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange;
   } else { // local temporary.
+    // If there is an LValue->RValue conversion, then the value of the
+    // reference type is used, not the reference.
+    if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetValExp)) {
+      if (ICE->getCastKind() == CK_LValueToRValue) {
+        return;
+      }
+    }
     S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref)
      << lhsType->isReferenceType() << diagRange;
   }
index ad27567fcd6469f421274dea41bf5c30eae7d735..f6ea9b2a738a5a711345771e4d06068f7def0bff 100644 (file)
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -std=c++11 %s
-// expected-no-diagnostics
 
 namespace PR26599 {
 template <typename>
@@ -20,3 +19,66 @@ void *&pointer() {
 }
 }
 
+namespace LocalTemporary {
+
+template <class T>
+class QMap {
+public:
+  T value(const T &t = T()) const {
+    return t;
+  }
+};
+
+struct A {};
+
+void test() {
+  QMap<A *> map;
+  map.value();
+}
+
+typedef int* ptr;
+ptr int1(const ptr &p = ptr()) {
+  return (p);
+}
+
+ptr int2(const ptr &p = nullptr) {
+  return p;
+}
+
+ptr int3() {
+  const ptr &p = ptr();
+  return p;
+}
+
+const int *int4(const int &x = 5) {
+  return &x;
+}
+
+const int *int5(const int &x) {
+  return &x;
+}
+
+const int *int6() {
+  const int &x = 11;  //expected-note{{binding reference variable 'x' here}}
+  return &x;  //expected-warning{{returning address of local temporary object}}
+}
+
+const int *int7(int x) {
+  const int &x2 = x;  // expected-note{{binding reference variable 'x2' here}}
+  const int &x3 = x2;
+  return &x2;  //  expected-warning{{address of stack memory associated with local variable 'x' returned}}
+}
+
+const int *int8(const int &x = 5) {
+  const int &x2 = x;
+  const int &x3 = x2;
+  return &x2;
+}
+
+const int *int9() {
+  const int &x = 5;  // expected-note{{binding reference variable 'x' here}}
+  const int &x2 = x;  // expected-note{{binding reference variable 'x2' here}}
+  const int &x3 = x2;
+  return &x2;  // expected-warning{{returning address of local temporary object}}
+}
+}