]> granicus.if.org Git - clang/commitdiff
Move detection of reference members binding to temporaries from building of
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 12 Jun 2013 21:51:50 +0000 (21:51 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 12 Jun 2013 21:51:50 +0000 (21:51 +0000)
CXXCtorInitializers to the point where we perform the questionable lifetime
extension. This exposed a selection of false negatives in the warning.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaInit.cpp
test/CXX/special/class.copy/p11.0x.copy.cpp
test/CXX/special/class.copy/p11.0x.move.cpp
test/CXX/special/class.ctor/p5-0x.cpp
test/CXX/temp/temp.param/p5.cpp
test/SemaCXX/warn-dangling-field.cpp

index 302ec8b08cde404dd649d494e6d4b5a05cfff6af..ac76e4d400bb72e78bd1372a5d132903c6b9b8cc 100644 (file)
@@ -5947,10 +5947,12 @@ def warn_init_ptr_member_to_parameter_addr : Warning<
   "initializing pointer member %0 with the stack address of parameter %1">,
   InGroup<DanglingField>;
 def warn_bind_ref_member_to_temporary : Warning<
-  "binding reference member %0 to a temporary value">,
+  "binding reference %select{|subobject of }1member %0 to a temporary value">,
   InGroup<DanglingField>;
 def note_ref_or_ptr_member_declared_here : Note<
   "%select{reference|pointer}0 member declared here">;
+def note_ref_subobject_of_member_declared_here : Note<
+  "member with reference subobject declared here">;
 
 // For non-floating point, expressions of the form x == x or x != x
 // should result in a warning, since these always evaluate to a constant.
index 008bb73dc804109103367b22d2e0abb20aecf2ce..5d6eab0f173a54ab70bc5d36c30d40ba6aa6a53a 100644 (file)
@@ -2479,15 +2479,7 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,
     }
   }
 
-  if (isa<MaterializeTemporaryExpr>(Init->IgnoreParens())) {
-    // Taking the address of a temporary will be diagnosed as a hard error.
-    if (IsPointer)
-      return;
-
-    S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary)
-      << Member << Init->getSourceRange();
-  } else if (const DeclRefExpr *DRE
-               = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {
     // We only warn when referring to a non-reference parameter declaration.
     const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl());
     if (!Parameter || Parameter->getType()->isReferenceType())
index b678f91bf721ababe116948fbbb3ac54532694f1..a4bccacb2da99f56069fda2967e69c8c7a3c0327 100644 (file)
@@ -2461,6 +2461,7 @@ InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
 {
   InitializedEntity Result;
   Result.Kind = EK_Base;
+  Result.Parent = 0;
   Result.Base = reinterpret_cast<uintptr_t>(Base);
   if (IsInheritedVirtualBase)
     Result.Base |= 0x01;
@@ -2553,6 +2554,7 @@ bool InitializedEntity::allowsNRVO() const {
 }
 
 unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
+  assert(getParent() != this);
   unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0;
   for (unsigned I = 0; I != Depth; ++I)
     OS << "`-";
@@ -5566,9 +5568,33 @@ InitializationSequence::Perform(Sema &S,
       // entity's lifetime.
       const ValueDecl *ExtendingDecl =
           getDeclForTemporaryLifetimeExtension(Entity);
-      if (ExtendingDecl)
+      if (ExtendingDecl) {
         performLifetimeExtension(CurInit.get(), ExtendingDecl);
 
+        // Warn if a field lifetime-extends a temporary.
+        if (isa<FieldDecl>(ExtendingDecl)) {
+          bool IsSubobjectMember = false;
+          for (const InitializedEntity *Ent = Entity.getParent(); Ent;
+               Ent = Ent->getParent()) {
+            if (Ent->getKind() != InitializedEntity::EK_Base) {
+              IsSubobjectMember = true;
+              break;
+            }
+          }
+          S.Diag(CurInit.get()->getExprLoc(),
+                 diag::warn_bind_ref_member_to_temporary)
+            << ExtendingDecl << CurInit.get()->getSourceRange()
+            << IsSubobjectMember;
+          if (IsSubobjectMember)
+            S.Diag(ExtendingDecl->getLocation(),
+                   diag::note_ref_subobject_of_member_declared_here);
+          else
+            S.Diag(ExtendingDecl->getLocation(),
+                   diag::note_ref_or_ptr_member_declared_here)
+              << /*IsPointer*/false;
+        }
+      }
+
       // Materialize the temporary into memory.
       MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr(
           Entity.getType().getNonReferenceType(), CurInit.get(),
index fab3b9dd7bf1191542f47c565f750a9593835c03..011c1e9a87606130df747cb4d4a0aa1c6dfd6028 100644 (file)
@@ -116,6 +116,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy c
 // -- a non-static data member of rvalue reference type
 struct RValue {
   int && ri = 1; // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
+  // expected-warning@-1{{binding reference member 'ri' to a temporary}} expected-note@-1 {{here}}
 };
 RValue RVa;
 RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}}
index ff9478be8b493ca19798436384b71bda38b194c7..ebcce491c404959ca308a1a00d646229639073de 100644 (file)
@@ -108,7 +108,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy c
 // The restriction on rvalue reference members applies to only the copy
 // constructor.
 struct RValue {
-  int &&ri = 1;
+  int &&ri = 1; // expected-warning {{binding reference member 'ri' to a temporary}} expected-note {{here}}
   RValue(RValue&&);
 };
 RValue::RValue(RValue&&) = default;
index 0f4add8c97423057000ad82d3ebcbe7534928987..2360345a4846adacfcae6b47e1e9bab0a8161092 100644 (file)
@@ -43,7 +43,7 @@ class NotDeleted2a { int &a = n; };
 NotDeleted2a nd2a;
 class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
 NotDeleted2b nd2b;
-class NotDeleted2c { int &&a = 0; };
+class NotDeleted2c { int &&a = 0; }; // expected-warning {{binding reference member 'a' to a temporary}} expected-note {{here}}
 NotDeleted2c nd2c;
 
 // - any non-variant non-static data member of const qualified type (or array
index 67efc4e48162544e8543a7f4a8d1e9c1f3c55110..c25868267e49413ad39ba5f4062debe3056eddd7 100644 (file)
@@ -1,14 +1,13 @@
 // RUN: %clang_cc1 -verify %s -std=c++11
-// expected-no-diagnostics
 
 template<const int I> struct S {
   decltype(I) n;
-  int &&r = I;
+  int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
 };
-S<5> s;
+S<5> s; // expected-note {{instantiation}}
 
 template<typename T, T v> struct U {
   decltype(v) n;
-  int &&r = v;
+  int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
 };
-U<const int, 6> u;
+U<const int, 6> u; // expected-note {{instantiation}}
index 95f8c61ebb77e9c56011da74e3bc77ef08d8c87c..eb65bd06692c9b1d21ebfe1c10df1106551f844d 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify -std=c++11 %s
 
 struct X {
   X(int);
@@ -35,3 +35,17 @@ template <typename T> struct S4 {
 
 template struct S4<int>; // no warning from this instantiation
 template struct S4<int&>; // expected-note {{in instantiation}}
+
+struct S5 {
+  const X &x; // expected-note {{here}}
+};
+S5 s5 = { 0 }; // ok, lifetime-extended
+
+struct S6 {
+  S5 s5; // expected-note {{here}}
+  S6() : s5 { 0 } {} // expected-warning {{binding reference subobject of member 's5' to a temporary}}
+};
+
+struct S7 : S5 {
+  S7() : S5 { 0 } {} // expected-warning {{binding reference member 'x' to a temporary}}
+};