<div dir="ltr">Nice!<div><br></div><div>This found one bug in the libc++abi tests (r337906), and started diagnosing the</div><div>dangling tuple reference case that libc++ worked hard to diagnose manually (r337905).</div><div><br></div><div>/Eric</div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Jul 23, 2018 at 6:55 PM Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Mon Jul 23 17:55:08 2018<br>
New Revision: 337790<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=337790&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=337790&view=rev</a><br>
Log:<br>
Warn if a local variable's initializer retains a pointer/reference to a<br>
non-lifetime-extended temporary object.<br>
<br>
Added:<br>
    cfe/trunk/test/SemaCXX/warn-dangling-local.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/lib/Sema/SemaInit.cpp<br>
    cfe/trunk/test/CXX/drs/dr16xx.cpp<br>
    cfe/trunk/test/SemaCXX/address-of-temporary.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=337790&r1=337789&r2=337790&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=337790&r1=337789&r2=337790&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Mon Jul 23 17:55:08 2018<br>
@@ -273,6 +273,10 @@ def OverloadedShiftOpParentheses: DiagGr<br>
 def DanglingElse: DiagGroup<"dangling-else">;<br>
 def DanglingField : DiagGroup<"dangling-field">;<br>
 def DanglingInitializerList : DiagGroup<"dangling-initializer-list">;<br>
+def ReturnStackAddress : DiagGroup<"return-stack-address">;<br>
+def Dangling : DiagGroup<"dangling", [DanglingField,<br>
+                                      DanglingInitializerList,<br>
+                                      ReturnStackAddress]>;<br>
 def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;<br>
 def ExpansionToDefined : DiagGroup<"expansion-to-defined">;<br>
 def FlagEnum : DiagGroup<"flag-enum">;<br>
@@ -407,7 +411,6 @@ def RedeclaredClassMember : DiagGroup<"r<br>
 def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">;<br>
 def RedundantMove : DiagGroup<"redundant-move">;<br>
 def Register : DiagGroup<"register", [DeprecatedRegister]>;<br>
-def ReturnStackAddress : DiagGroup<"return-stack-address">;<br>
 def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;<br>
 def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>;<br>
 def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy",<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=337790&r1=337789&r2=337790&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=337790&r1=337789&r2=337790&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 23 17:55:08 2018<br>
@@ -1845,10 +1845,6 @@ def err_reference_bind_failed : Error<<br>
   "type $|could not bind to %select{rvalue|lvalue}1 of incompatible type}0,2">;<br>
 def err_reference_bind_init_list : Error<<br>
   "reference to type %0 cannot bind to an initializer list">;<br>
-def warn_temporary_array_to_pointer_decay : Warning<<br>
-  "pointer is initialized by a temporary array, which will be destroyed at the "<br>
-  "end of the full-expression">,<br>
-  InGroup<DiagGroup<"address-of-array-temporary">>;<br>
 def err_init_list_bad_dest_type : Error<<br>
   "%select{|non-aggregate }0type %1 cannot be initialized with an initializer "<br>
   "list">;<br>
@@ -7876,15 +7872,31 @@ def warn_init_ptr_member_to_parameter_ad<br>
 def note_ref_or_ptr_member_declared_here : Note<<br>
   "%select{reference|pointer}0 member declared here">;<br>
<br>
-def err_bind_ref_member_to_temporary : Error<<br>
+def err_dangling_member : Error<<br>
   "%select{reference|backing array for 'std::initializer_list'}2 "<br>
   "%select{|subobject of }1member %0 "<br>
   "%select{binds to|is}2 a temporary object "<br>
-  "whose lifetime would be shorter than the constructed object">;<br>
+  "whose lifetime would be shorter than the lifetime of "<br>
+  "the constructed object">;<br>
+def warn_dangling_member : Warning<<br>
+  "%select{reference|backing array for 'std::initializer_list'}2 "<br>
+  "%select{|subobject of }1member %0 "<br>
+  "%select{binds to|is}2 a temporary object "<br>
+  "whose lifetime is shorter than the lifetime of the constructed object">,<br>
+  InGroup<DanglingField>;<br>
 def note_lifetime_extending_member_declared_here : Note<<br>
   "%select{%select{reference|'std::initializer_list'}0 member|"<br>
   "member with %select{reference|'std::initializer_list'}0 subobject}1 "<br>
   "declared here">;<br>
+def warn_dangling_variable : Warning<<br>
+  "%select{temporary %select{whose address is used as value of|bound to}3 "<br>
+  "%select{%select{|reference }3member of local variable|"<br>
+  "local %select{variable|reference}3}1|"<br>
+  "array backing "<br>
+  "%select{initializer list subobject of local variable|"<br>
+  "local initializer list}1}0 "<br>
+  "%2 will be destroyed at the end of the full-expression">,<br>
+  InGroup<Dangling>;<br>
 def warn_new_dangling_reference : Warning<<br>
   "temporary bound to reference member of allocated object "<br>
   "will be destroyed at the end of the full-expression">,<br>
@@ -7895,16 +7907,12 @@ def warn_new_dangling_initializer_list :<br>
   "the allocated initializer list}0 "<br>
   "will be destroyed at the end of the full-expression">,<br>
   InGroup<DanglingInitializerList>;<br>
-def warn_unsupported_temporary_not_extended : Warning<<br>
-  "sorry, lifetime extension of temporary created "<br>
-  "by aggregate initialization using default member initializer "<br>
-  "is not supported; lifetime of temporary "<br>
-  "will end at the end of the full-expression">, InGroup<DanglingField>;<br>
-def warn_unsupported_init_list_not_extended : Warning<<br>
-  "sorry, lifetime extension of backing array of initializer list created "<br>
+def warn_unsupported_lifetime_extension : Warning<<br>
+  "sorry, lifetime extension of "<br>
+  "%select{temporary|backing array of initializer list}0 created "<br>
   "by aggregate initialization using default member initializer "<br>
-  "is not supported; lifetime of backing array will end at the end of the "<br>
-  "full-expression">, InGroup<DanglingInitializerList>;<br>
+  "is not supported; lifetime of %select{temporary|backing array}0 "<br>
+  "will end at the end of the full-expression">, InGroup<Dangling>;<br>
<br>
 // For non-floating point, expressions of the form x == x or x != x<br>
 // should result in a warning, since these always evaluate to a constant.<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaInit.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=337790&r1=337789&r2=337790&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=337790&r1=337789&r2=337790&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Jul 23 17:55:08 2018<br>
@@ -6167,49 +6167,6 @@ PerformConstructorInitialization(Sema &S<br>
   return CurInit;<br>
 }<br>
<br>
-/// Determine whether the specified InitializedEntity definitely has a lifetime<br>
-/// longer than the current full-expression. Conservatively returns false if<br>
-/// it's unclear.<br>
-static bool<br>
-InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {<br>
-  const InitializedEntity *Top = &Entity;<br>
-  while (Top->getParent())<br>
-    Top = Top->getParent();<br>
-<br>
-  switch (Top->getKind()) {<br>
-  case InitializedEntity::EK_Variable:<br>
-  case InitializedEntity::EK_Result:<br>
-  case InitializedEntity::EK_StmtExprResult:<br>
-  case InitializedEntity::EK_Exception:<br>
-  case InitializedEntity::EK_Member:<br>
-  case InitializedEntity::EK_Binding:<br>
-  case InitializedEntity::EK_New:<br>
-  case InitializedEntity::EK_Base:<br>
-  case InitializedEntity::EK_Delegating:<br>
-    return true;<br>
-<br>
-  case InitializedEntity::EK_ArrayElement:<br>
-  case InitializedEntity::EK_VectorElement:<br>
-  case InitializedEntity::EK_BlockElement:<br>
-  case InitializedEntity::EK_LambdaToBlockConversionBlockElement:<br>
-  case InitializedEntity::EK_ComplexElement:<br>
-    // Could not determine what the full initialization is. Assume it might not<br>
-    // outlive the full-expression.<br>
-    return false;<br>
-<br>
-  case InitializedEntity::EK_Parameter:<br>
-  case InitializedEntity::EK_Parameter_CF_Audited:<br>
-  case InitializedEntity::EK_Temporary:<br>
-  case InitializedEntity::EK_LambdaCapture:<br>
-  case InitializedEntity::EK_CompoundLiteralInit:<br>
-  case InitializedEntity::EK_RelatedResult:<br>
-    // The entity being initialized might not outlive the full-expression.<br>
-    return false;<br>
-  }<br>
-<br>
-  llvm_unreachable("unknown entity kind");<br>
-}<br>
-<br>
 namespace {<br>
 enum LifetimeKind {<br>
   /// The lifetime of a temporary bound to this entity ends at the end of the<br>
@@ -6393,6 +6350,13 @@ static bool isVarOnPath(IndirectLocalPat<br>
   return false;<br>
 }<br>
<br>
+static bool pathContainsInit(IndirectLocalPath &Path) {<br>
+  return std::any_of(Path.begin(), Path.end(), [=](IndirectLocalPathEntry E) {<br>
+    return E.Kind == IndirectLocalPathEntry::DefaultInit ||<br>
+           E.Kind == IndirectLocalPathEntry::VarInit;<br>
+  });<br>
+}<br>
+<br>
 static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,<br>
                                              Expr *Init, LocalVisitor Visit,<br>
                                              bool RevisitSubinits);<br>
@@ -6660,6 +6624,12 @@ static void visitLocalsRetainedByInitial<br>
     // If the initializer is the address of a local, we could have a lifetime<br>
     // problem.<br>
     if (UO->getOpcode() == UO_AddrOf) {<br>
+      // If this is &rvalue, then it's ill-formed and we have already diagnosed<br>
+      // it. Don't produce a redundant warning about the lifetime of the<br>
+      // temporary.<br>
+      if (isa<MaterializeTemporaryExpr>(UO->getSubExpr()))<br>
+        return;<br>
+<br>
       Path.push_back({IndirectLocalPathEntry::AddressOf, UO});<br>
       visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(),<br>
                                             RK_ReferenceBinding, Visit);<br>
@@ -6761,9 +6731,14 @@ void Sema::checkInitializerLifetime(cons<br>
<br>
     case LK_Extended: {<br>
       auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);<br>
-      if (!MTE)<br>
-        // FIXME: Warn on this.<br>
+      if (!MTE) {<br>
+        // The initialized entity has lifetime beyond the full-expression,<br>
+        // and the local entity does too, so don't warn.<br>
+        //<br>
+        // FIXME: We should consider warning if a static / thread storage<br>
+        // duration variable retains an automatic storage duration local.<br>
         return false;<br>
+      }<br>
<br>
       // Lifetime-extend the temporary.<br>
       if (Path.empty()) {<br>
@@ -6779,17 +6754,21 @@ void Sema::checkInitializerLifetime(cons<br>
         // We're supposed to lifetime-extend the temporary along this path (per<br>
         // the resolution of DR1815), but we don't support that yet.<br>
         //<br>
-        // FIXME: Properly handle these situations.<br>
-        // For the default member initializer case, perhaps the easiest approach<br>
+        // FIXME: Properly handle this situation. Perhaps the easiest approach<br>
         // would be to clone the initializer expression on each use that would<br>
         // lifetime extend its temporaries.<br>
-        Diag(DiagLoc, RK == RK_ReferenceBinding<br>
-                          ? diag::warn_unsupported_temporary_not_extended<br>
-                          : diag::warn_unsupported_init_list_not_extended)<br>
-            << DiagRange;<br>
+        Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)<br>
+            << RK << DiagRange;<br>
       } else {<br>
-        // FIXME: Warn on this.<br>
-        return false;<br>
+        // If the path goes through the initialization of a variable or field,<br>
+        // it can't possibly reach a temporary created in this full-expression.<br>
+        // We will have already diagnosed any problems with the initializer.<br>
+        if (pathContainsInit(Path))<br>
+          return false;<br>
+<br>
+        Diag(DiagLoc, diag::warn_dangling_variable)<br>
+            << RK << !Entity.getParent() << ExtendingEntity->getDecl()<br>
+            << Init->isGLValue() << DiagRange;<br>
       }<br>
       break;<br>
     }<br>
@@ -6802,7 +6781,9 @@ void Sema::checkInitializerLifetime(cons<br>
         if (auto *ExtendingDecl =<br>
                 ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {<br>
           bool IsSubobjectMember = ExtendingEntity != &Entity;<br>
-          Diag(DiagLoc, diag::err_bind_ref_member_to_temporary)<br>
+          Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path)<br>
+                            ? diag::err_dangling_member<br>
+                            : diag::warn_dangling_member)<br>
               << ExtendingDecl << IsSubobjectMember << RK << DiagRange;<br>
           // Don't bother adding a note pointing to the field if we're inside<br>
           // its default member initializer; our primary diagnostic points to<br>
@@ -6826,9 +6807,7 @@ void Sema::checkInitializerLifetime(cons<br>
         // Paths via a default initializer can only occur during error recovery<br>
         // (there's no other way that a default initializer can refer to a<br>
         // local). Don't produce a bogus warning on those cases.<br>
-        if (std::any_of(Path.begin(), Path.end(), [](IndirectLocalPathEntry E) {<br>
-              return E.Kind == IndirectLocalPathEntry::DefaultInit;<br>
-            }))<br>
+        if (pathContainsInit(Path))<br>
           return false;<br>
<br>
         auto *DRE = dyn_cast<DeclRefExpr>(L);<br>
@@ -6858,7 +6837,7 @@ void Sema::checkInitializerLifetime(cons<br>
         Diag(DiagLoc, RK == RK_ReferenceBinding<br>
                           ? diag::warn_new_dangling_reference<br>
                           : diag::warn_new_dangling_initializer_list)<br>
-            << (ExtendingEntity != &Entity) << DiagRange;<br>
+            << !Entity.getParent() << DiagRange;<br>
       } else {<br>
         // We can't determine if the allocation outlives the local declaration.<br>
         return false;<br>
@@ -7184,21 +7163,6 @@ InitializationSequence::Perform(Sema &S,<br>
     return ExprError();<br>
   }<br>
<br>
-  // Diagnose cases where we initialize a pointer to an array temporary, and the<br>
-  // pointer obviously outlives the temporary.<br>
-  // FIXME: Fold this into checkInitializerLifetime.<br>
-  if (Args.size() == 1 && Args[0]->getType()->isArrayType() &&<br>
-      Entity.getType()->isPointerType() &&<br>
-      InitializedEntityOutlivesFullExpression(Entity)) {<br>
-    const Expr *Init = Args[0]->skipRValueSubobjectAdjustments();<br>
-    if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init))<br>
-      Init = MTE->GetTemporaryExpr();<br>
-    Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context);<br>
-    if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary)<br>
-      S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay)<br>
-        << Init->getSourceRange();<br>
-  }<br>
-<br>
   QualType DestType = Entity.getType().getNonReferenceType();<br>
   // FIXME: Ugly hack around the fact that Entity.getType() is not<br>
   // the same as Entity.getDecl()->getType() in cases involving type merging,<br>
<br>
Modified: cfe/trunk/test/CXX/drs/dr16xx.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr16xx.cpp?rev=337790&r1=337789&r2=337790&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr16xx.cpp?rev=337790&r1=337789&r2=337790&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/drs/dr16xx.cpp (original)<br>
+++ cfe/trunk/test/CXX/drs/dr16xx.cpp Mon Jul 23 17:55:08 2018<br>
@@ -300,7 +300,7 @@ namespace dr1696 { // dr1696: 7<br>
 #if __cplusplus >= 201103L<br>
   struct B {<br>
     A &&a; // expected-note {{declared here}}<br>
-    B() : a{} {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the constructed object}}<br>
+    B() : a{} {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}<br>
   } b;<br>
 #endif<br>
<br>
@@ -308,7 +308,7 @@ namespace dr1696 { // dr1696: 7<br>
     C();<br>
     const A &a; // expected-note {{declared here}}<br>
   };<br>
-  C::C() : a(A()) {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the constructed object}}<br>
+  C::C() : a(A()) {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}<br>
<br>
 #if __cplusplus >= 201103L<br>
   // This is OK in C++14 onwards, per DR1815, though we don't support that yet:<br>
<br>
Modified: cfe/trunk/test/SemaCXX/address-of-temporary.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/address-of-temporary.cpp?rev=337790&r1=337789&r2=337790&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/address-of-temporary.cpp?rev=337790&r1=337789&r2=337790&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/address-of-temporary.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/address-of-temporary.cpp Mon Jul 23 17:55:08 2018<br>
@@ -26,11 +26,12 @@ namespace PointerToArrayDecay {<br>
   template<typename T> void consume(T);<br>
   struct S { int *p; };<br>
<br>
-  void g0() { int *p = Y().a; } // expected-warning{{pointer is initialized by a temporary array}}<br>
-  void g1() { int *p = Y{}.a; } // expected-warning{{pointer is initialized by a temporary array}}<br>
-  void g2() { int *p = A{}; } // expected-warning{{pointer is initialized by a temporary array}}<br>
-  void g3() { int *p = (A){}; } // expected-warning{{pointer is initialized by a temporary array}}<br>
-  void g4() { Z *p = AZ{}; } // expected-warning{{pointer is initialized by a temporary array}}<br>
+  void g0() { int *p = Y().a; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void g1() { int *p = Y{}.a; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void g2() { int *p = A{}; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void g3() { int *p = (A){}; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void g4() { Z *p = AZ{}; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void g5() { Z *p = &(Z&)(AZ{}[0]); } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
<br>
   void h0() { consume(Y().a); }<br>
   void h1() { consume(Y{}.a); }<br>
@@ -38,10 +39,10 @@ namespace PointerToArrayDecay {<br>
   void h3() { consume((A){}); }<br>
   void h4() { consume(AZ{}); }<br>
<br>
-  void i0() { S s = { Y().a }; } // expected-warning{{pointer is initialized by a temporary array}}<br>
-  void i1() { S s = { Y{}.a }; } // expected-warning{{pointer is initialized by a temporary array}}<br>
-  void i2() { S s = { A{} }; } // expected-warning{{pointer is initialized by a temporary array}}<br>
-  void i3() { S s = { (A){} }; } // expected-warning{{pointer is initialized by a temporary array}}<br>
+  void i0() { S s = { Y().a }; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void i1() { S s = { Y{}.a }; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void i2() { S s = { A{} }; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
+  void i3() { S s = { (A){} }; } // expected-warning{{will be destroyed at the end of the full-expression}}<br>
<br>
   void j0() { (void)S { Y().a }; }<br>
   void j1() { (void)S { Y{}.a }; }<br>
<br>
Added: cfe/trunk/test/SemaCXX/warn-dangling-local.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-dangling-local.cpp?rev=337790&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-dangling-local.cpp?rev=337790&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/warn-dangling-local.cpp (added)<br>
+++ cfe/trunk/test/SemaCXX/warn-dangling-local.cpp Mon Jul 23 17:55:08 2018<br>
@@ -0,0 +1,20 @@<br>
+// RUN: %clang_cc1 -verify -std=c++11 %s<br>
+<br>
+using T = int[];<br>
+<br>
+void f() {<br>
+  int *p = &(int&)(int&&)0; // expected-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}<br>
+<br>
+  int *q = (int *const &)T{1, 2, 3}; // expected-warning {{temporary whose address is used as value of local variable 'q' will be destroyed at the end of the full-expression}}<br>
+<br>
+  // FIXME: We don't warn here because the 'int*' temporary is not const, but<br>
+  // it also can't have actually changed since it was created, so we could<br>
+  // still warn.<br>
+  int *r = (int *&&)T{1, 2, 3};<br>
+<br>
+  // FIXME: The wording of this warning is not quite right. There are two<br>
+  // temporaries here: an 'int* const' temporary that points to the array, and<br>
+  // is lifetime-extended, and an array temporary that the pointer temporary<br>
+  // points to, which doesn't live long enough.<br>
+  int *const &s = (int *const &)T{1, 2, 3}; // expected-warning {{temporary bound to local reference 's' will be destroyed at the end of the full-expression}}<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>