<div dir="ltr">Reverted in r337671</div><br><div class="gmail_quote"><div dir="ltr">On Mon, Jul 23, 2018 at 8:24 AM Ilya Biryukov <<a href="mailto:ibiryukov@google.com">ibiryukov@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Richard,<div><br></div><div>this commit seems to cause invalid warning in the following example:<br></div><div><div><br></div><div>struct foo {</div><div>  foo(char *x) : x_(&x[10]) {} // </div><div>private:</div><div>  char *x_; </div><div>};</div></div><div><br></div><div>The warning itself:</div><div><div>1.cpp:2:21: warning: initializing pointer member 'x_' with the stack address of parameter 'x' [-Wdangling-field]</div><div><br></div></div><div>I'll revert the change to unbreak our integrate.</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Sat, Jul 21, 2018 at 12:31 AM Richard Smith via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">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: Fri Jul 20 15:25:55 2018<br>
New Revision: 337627<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=337627&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=337627&view=rev</a><br>
Log:<br>
Fold dangling-field warning into general initialization lifetime checks.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaInit.cpp<br>
    cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp<br>
    cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp<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=337627&r1=337626&r2=337627&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=337627&r1=337626&r2=337627&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jul 20 15:25:55 2018<br>
@@ -7870,11 +7870,11 @@ def note_ref_var_local_bind : Note<<br>
 // Check for initializing a member variable with the address or a reference to<br>
 // a constructor parameter.<br>
 def warn_bind_ref_member_to_parameter : Warning<<br>
-  "binding reference member %0 to stack allocated parameter %1">,<br>
-  InGroup<DanglingField>;<br>
+  "binding reference member %0 to stack allocated "<br>
+  "%select{variable|parameter}2 %1">, InGroup<DanglingField>;<br>
 def warn_init_ptr_member_to_parameter_addr : Warning<<br>
-  "initializing pointer member %0 with the stack address of parameter %1">,<br>
-  InGroup<DanglingField>;<br>
+  "initializing pointer member %0 with the stack address of "<br>
+  "%select{variable|parameter}2 %1">, InGroup<DanglingField>;<br>
 def note_ref_or_ptr_member_declared_here : Note<<br>
   "%select{reference|pointer}0 member declared here">;<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=337627&r1=337626&r2=337627&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=337627&r1=337626&r2=337627&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Jul 20 15:25:55 2018<br>
@@ -3946,53 +3946,6 @@ Sema::BuildMemInitializer(Decl *Construc<br>
   return BuildBaseInitializer(BaseType, TInfo, Init, ClassDecl, EllipsisLoc);<br>
 }<br>
<br>
-/// Checks a member initializer expression for cases where reference (or<br>
-/// pointer) members are bound to by-value parameters (or their addresses).<br>
-static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member,<br>
-                                               Expr *Init,<br>
-                                               SourceLocation IdLoc) {<br>
-  QualType MemberTy = Member->getType();<br>
-<br>
-  // We only handle pointers and references currently.<br>
-  // FIXME: Would this be relevant for ObjC object pointers? Or block pointers?<br>
-  if (!MemberTy->isReferenceType() && !MemberTy->isPointerType())<br>
-    return;<br>
-<br>
-  const bool IsPointer = MemberTy->isPointerType();<br>
-  if (IsPointer) {<br>
-    if (const UnaryOperator *Op<br>
-          = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) {<br>
-      // The only case we're worried about with pointers requires taking the<br>
-      // address.<br>
-      if (Op->getOpcode() != UO_AddrOf)<br>
-        return;<br>
-<br>
-      Init = Op->getSubExpr();<br>
-    } else {<br>
-      // We only handle address-of expression initializers for pointers.<br>
-      return;<br>
-    }<br>
-  }<br>
-<br>
-  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {<br>
-    // We only warn when referring to a non-reference parameter declaration.<br>
-    const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl());<br>
-    if (!Parameter || Parameter->getType()->isReferenceType())<br>
-      return;<br>
-<br>
-    S.Diag(Init->getExprLoc(),<br>
-           IsPointer ? diag::warn_init_ptr_member_to_parameter_addr<br>
-                     : diag::warn_bind_ref_member_to_parameter)<br>
-      << Member << Parameter << Init->getSourceRange();<br>
-  } else {<br>
-    // Other initializers are fine.<br>
-    return;<br>
-  }<br>
-<br>
-  S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here)<br>
-    << (unsigned)IsPointer;<br>
-}<br>
-<br>
 MemInitResult<br>
 Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,<br>
                              SourceLocation IdLoc) {<br>
@@ -4047,8 +4000,6 @@ Sema::BuildMemberInitializer(ValueDecl *<br>
     if (MemberInit.isInvalid())<br>
       return true;<br>
<br>
-    CheckForDanglingReferenceOrPointer(*this, Member, MemberInit.get(), IdLoc);<br>
-<br>
     // C++11 [class.base.init]p7:<br>
     //   The initialization of each base and member constitutes a<br>
     //   full-expression.<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=337627&r1=337626&r2=337627&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=337627&r1=337626&r2=337627&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Jul 20 15:25:55 2018<br>
@@ -6227,7 +6227,7 @@ using LifetimeResult =<br>
 /// Determine the declaration which an initialized entity ultimately refers to,<br>
 /// for the purpose of lifetime-extending a temporary bound to a reference in<br>
 /// the initialization of \p Entity.<br>
-static LifetimeResult getEntityForTemporaryLifetimeExtension(<br>
+static LifetimeResult getEntityLifetime(<br>
     const InitializedEntity *Entity,<br>
     const InitializedEntity *InitField = nullptr) {<br>
   // C++11 [class.temporary]p5:<br>
@@ -6239,8 +6239,7 @@ static LifetimeResult getEntityForTempor<br>
   case InitializedEntity::EK_Member:<br>
     // For subobjects, we look at the complete object.<br>
     if (Entity->getParent())<br>
-      return getEntityForTemporaryLifetimeExtension(Entity->getParent(),<br>
-                                                    Entity);<br>
+      return getEntityLifetime(Entity->getParent(), Entity);<br>
<br>
     //   except:<br>
     // C++17 [class.base.init]p8:<br>
@@ -6291,14 +6290,12 @@ static LifetimeResult getEntityForTempor<br>
<br>
   case InitializedEntity::EK_ArrayElement:<br>
     // For subobjects, we look at the complete object.<br>
-    return getEntityForTemporaryLifetimeExtension(Entity->getParent(),<br>
-                                                  InitField);<br>
+    return getEntityLifetime(Entity->getParent(), InitField);<br>
<br>
   case InitializedEntity::EK_Base:<br>
     // For subobjects, we look at the complete object.<br>
     if (Entity->getParent())<br>
-      return getEntityForTemporaryLifetimeExtension(Entity->getParent(),<br>
-                                                    InitField);<br>
+      return getEntityLifetime(Entity->getParent(), InitField);<br>
     return {InitField, LK_MemInitializer};<br>
<br>
   case InitializedEntity::EK_Delegating:<br>
@@ -6311,46 +6308,61 @@ static LifetimeResult getEntityForTempor<br>
   case InitializedEntity::EK_BlockElement:<br>
   case InitializedEntity::EK_LambdaToBlockConversionBlockElement:<br>
   case InitializedEntity::EK_LambdaCapture:<br>
-  case InitializedEntity::EK_Exception:<br>
   case InitializedEntity::EK_VectorElement:<br>
   case InitializedEntity::EK_ComplexElement:<br>
     return {nullptr, LK_FullExpression};<br>
+<br>
+  case InitializedEntity::EK_Exception:<br>
+    // FIXME: Can we diagnose lifetime problems with exceptions?<br>
+    return {nullptr, LK_FullExpression};<br>
   }<br>
   llvm_unreachable("unknown entity kind");<br>
 }<br>
<br>
 namespace {<br>
-enum ExtensionKind {<br>
+enum ReferenceKind {<br>
   /// Lifetime would be extended by a reference binding to a temporary.<br>
-  EK_ReferenceBinding,<br>
+  RK_ReferenceBinding,<br>
   /// Lifetime would be extended by a std::initializer_list object binding to<br>
   /// its backing array.<br>
-  EK_StdInitializerList,<br>
+  RK_StdInitializerList,<br>
 };<br>
-using IndirectTemporaryPathEntry =<br>
-    llvm::PointerUnion<CXXDefaultInitExpr *, ValueDecl *>;<br>
-using IndirectTemporaryPath = llvm::SmallVectorImpl<IndirectTemporaryPathEntry>;<br>
+<br>
+/// A temporary or local variable.<br>
+using Local = llvm::PointerUnion<MaterializeTemporaryExpr*, ValueDecl*>;<br>
+<br>
+/// Expressions we stepped over when looking for the local state. Any steps<br>
+/// that would inhibit lifetime extension or take us out of subexpressions of<br>
+/// the initializer are included.<br>
+struct IndirectLocalPathEntry {<br>
+  enum {<br>
+    DefaultInit,<br>
+    AddressOf,<br>
+  } Kind;<br>
+  Expr *E;<br>
+};<br>
+<br>
+using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>;<br>
<br>
 struct RevertToOldSizeRAII {<br>
-  IndirectTemporaryPath &Path;<br>
+  IndirectLocalPath &Path;<br>
   unsigned OldSize = Path.size();<br>
-  RevertToOldSizeRAII(IndirectTemporaryPath &Path) : Path(Path) {}<br>
+  RevertToOldSizeRAII(IndirectLocalPath &Path) : Path(Path) {}<br>
   ~RevertToOldSizeRAII() { Path.resize(OldSize); }<br>
 };<br>
 }<br>
<br>
-template <typename TemporaryVisitor><br>
-static void visitTemporariesExtendedByInitializer(IndirectTemporaryPath &Path,<br>
-                                                  Expr *Init,<br>
-                                                  TemporaryVisitor Visit);<br>
-<br>
-/// Visit the temporaries whose lifetimes would be extended by binding a<br>
-/// reference to the glvalue expression \c Init.<br>
-template <typename TemporaryVisitor><br>
-static void<br>
-visitTemporariesExtendedByReferenceBinding(IndirectTemporaryPath &Path,<br>
-                                           Expr *Init, ExtensionKind EK,<br>
-                                           TemporaryVisitor Visit) {<br>
+template <typename LocalVisitor><br>
+static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,<br>
+                                             Expr *Init, LocalVisitor Visit,<br>
+                                             bool RevisitSubinits);<br>
+<br>
+/// Visit the locals that would be reachable through a reference bound to the<br>
+/// glvalue expression \c Init.<br>
+template <typename LocalVisitor><br>
+static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,<br>
+                                                  Expr *Init, ReferenceKind RK,<br>
+                                                  LocalVisitor Visit) {<br>
   RevertToOldSizeRAII RAII(Path);<br>
<br>
   // Walk past any constructs which we can lifetime-extend across.<br>
@@ -6382,7 +6394,7 @@ visitTemporariesExtendedByReferenceBindi<br>
     // Step into CXXDefaultInitExprs so we can diagnose cases where a<br>
     // constructor inherits one as an implicit mem-initializer.<br>
     if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {<br>
-      Path.push_back(DIE);<br>
+      Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE});<br>
       Init = DIE->getExpr();<br>
<br>
       if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))<br>
@@ -6391,25 +6403,36 @@ visitTemporariesExtendedByReferenceBindi<br>
   } while (Init != Old);<br>
<br>
   if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {<br>
-    if (Visit(Path, MTE, EK))<br>
-      visitTemporariesExtendedByInitializer(Path, MTE->GetTemporaryExpr(),<br>
-                                            Visit);<br>
+    if (Visit(Path, Local(MTE), RK))<br>
+      visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit,<br>
+                                       true);<br>
+  }<br>
+<br>
+  // If we find the name of a local non-reference parameter, we could have a<br>
+  // lifetime problem.<br>
+  if (auto *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) {<br>
+    auto *VD = dyn_cast<VarDecl>(DRE->getDecl());<br>
+    if (VD && VD->hasLocalStorage() &&<br>
+        !DRE->refersToEnclosingVariableOrCapture()) {<br>
+      // FIXME: Recurse to the initializer of a local reference.<br>
+      if (!VD->getType()->isReferenceType())<br>
+        Visit(Path, Local(VD), RK);<br>
+    }<br>
   }<br>
 }<br>
<br>
-/// Visit the temporaries whose lifetimes would be extended by<br>
-/// lifetime-extending the object initialized by the prvalue expression \c<br>
-/// Init.<br>
-template <typename TemporaryVisitor><br>
-static void visitTemporariesExtendedByInitializer(IndirectTemporaryPath &Path,<br>
-                                                  Expr *Init,<br>
-                                                  TemporaryVisitor Visit) {<br>
+/// Visit the locals that would be reachable through an object initialized by<br>
+/// the prvalue expression \c Init.<br>
+template <typename LocalVisitor><br>
+static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,<br>
+                                             Expr *Init, LocalVisitor Visit,<br>
+                                             bool RevisitSubinits) {<br>
   RevertToOldSizeRAII RAII(Path);<br>
<br>
   // Step into CXXDefaultInitExprs so we can diagnose cases where a<br>
   // constructor inherits one as an implicit mem-initializer.<br>
   if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {<br>
-    Path.push_back(DIE);<br>
+    Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE});<br>
     Init = DIE->getExpr();<br>
<br>
     if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))<br>
@@ -6426,17 +6449,24 @@ static void visitTemporariesExtendedByIn<br>
   //   initializing an initializer_list object from the array extends the<br>
   //   lifetime of the array exactly like binding a reference to a temporary.<br>
   if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))<br>
-    return visitTemporariesExtendedByReferenceBinding(<br>
-        Path, ILE->getSubExpr(), EK_StdInitializerList, Visit);<br>
+    return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(),<br>
+                                                 RK_StdInitializerList, Visit);<br>
<br>
   if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {<br>
+    // We already visited the elements of this initializer list while<br>
+    // performing the initialization. Don't visit them again unless we've<br>
+    // changed the lifetime of the initialized entity.<br>
+    if (!RevisitSubinits)<br>
+      return;<br>
+<br>
     if (ILE->isTransparent())<br>
-      return visitTemporariesExtendedByInitializer(Path, ILE->getInit(0),<br>
-                                                   Visit);<br>
+      return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit,<br>
+                                              RevisitSubinits);<br>
<br>
     if (ILE->getType()->isArrayType()) {<br>
       for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)<br>
-        visitTemporariesExtendedByInitializer(Path, ILE->getInit(I), Visit);<br>
+        visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit,<br>
+                                         RevisitSubinits);<br>
       return;<br>
     }<br>
<br>
@@ -6448,8 +6478,8 @@ static void visitTemporariesExtendedByIn<br>
       // bound to temporaries, those temporaries are also lifetime-extended.<br>
       if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&<br>
           ILE->getInitializedFieldInUnion()->getType()->isReferenceType())<br>
-        visitTemporariesExtendedByReferenceBinding(Path, ILE->getInit(0),<br>
-                                                   EK_ReferenceBinding, Visit);<br>
+        visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0),<br>
+                                              RK_ReferenceBinding, Visit);<br>
       else {<br>
         unsigned Index = 0;<br>
         for (const auto *I : RD->fields()) {<br>
@@ -6459,25 +6489,38 @@ static void visitTemporariesExtendedByIn<br>
             continue;<br>
           Expr *SubInit = ILE->getInit(Index);<br>
           if (I->getType()->isReferenceType())<br>
-            visitTemporariesExtendedByReferenceBinding(<br>
-                Path, SubInit, EK_ReferenceBinding, Visit);<br>
+            visitLocalsRetainedByReferenceBinding(Path, SubInit,<br>
+                                                  RK_ReferenceBinding, Visit);<br>
           else<br>
             // This might be either aggregate-initialization of a member or<br>
             // initialization of a std::initializer_list object. Regardless,<br>
             // we should recursively lifetime-extend that initializer.<br>
-            visitTemporariesExtendedByInitializer(Path, SubInit, Visit);<br>
+            visitLocalsRetainedByInitializer(Path, SubInit, Visit,<br>
+                                             RevisitSubinits);<br>
           ++Index;<br>
         }<br>
       }<br>
     }<br>
+    return;<br>
+  }<br>
+<br>
+  // If the initializer is the address of a local, we could have a lifetime<br>
+  // problem.<br>
+  if (auto *Op = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) {<br>
+    if (Op->getOpcode() == UO_AddrOf) {<br>
+      Path.push_back({IndirectLocalPathEntry::AddressOf, Op});<br>
+      Init = Op->getSubExpr();<br>
+      return visitLocalsRetainedByReferenceBinding(Path, Init,<br>
+                                                   RK_ReferenceBinding, Visit);<br>
+    }<br>
   }<br>
 }<br>
<br>
 /// Determine whether this is an indirect path to a temporary that we are<br>
 /// supposed to lifetime-extend along (but don't).<br>
-static bool shouldLifetimeExtendThroughPath(const IndirectTemporaryPath &Path) {<br>
+static bool shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {<br>
   for (auto Elem : Path) {<br>
-    if (!Elem.is<CXXDefaultInitExpr*>())<br>
+    if (Elem.Kind != IndirectLocalPathEntry::DefaultInit)<br>
       return false;<br>
   }<br>
   return true;<br>
@@ -6485,7 +6528,7 @@ static bool shouldLifetimeExtendThroughP<br>
<br>
 void Sema::checkInitializerLifetime(const InitializedEntity &Entity,<br>
                                     Expr *Init) {<br>
-  LifetimeResult LR = getEntityForTemporaryLifetimeExtension(&Entity);<br>
+  LifetimeResult LR = getEntityLifetime(&Entity);<br>
   LifetimeKind LK = LR.getInt();<br>
   const InitializedEntity *ExtendingEntity = LR.getPointer();<br>
<br>
@@ -6494,9 +6537,54 @@ void Sema::checkInitializerLifetime(cons<br>
   if (LK == LK_FullExpression)<br>
     return;<br>
<br>
-  auto TemporaryVisitor = [&](IndirectTemporaryPath &Path,<br>
-                              MaterializeTemporaryExpr *MTE,<br>
-                              ExtensionKind EK) -> bool {<br>
+  auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L,<br>
+                              ReferenceKind RK) -> bool {<br>
+    // If we found a path to a local variable or similar, check whether the<br>
+    // initialized object will outlive it.<br>
+    if (auto *VD = L.dyn_cast<ValueDecl*>()) {<br>
+      switch (LK) {<br>
+      case LK_FullExpression:<br>
+        llvm_unreachable("already handled this");<br>
+<br>
+      case LK_Extended:<br>
+        break;<br>
+<br>
+      case LK_MemInitializer: {<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>
+          break;<br>
+<br>
+        if (auto *Member =<br>
+                ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {<br>
+          bool AddressTaken =<br>
+              !Path.empty() &&<br>
+              Path.back().Kind == IndirectLocalPathEntry::AddressOf;<br>
+          Diag(Init->getExprLoc(),<br>
+               AddressTaken ? diag::warn_init_ptr_member_to_parameter_addr<br>
+                            : diag::warn_bind_ref_member_to_parameter)<br>
+              << Member << VD << isa<ParmVarDecl>(VD) << Init->getSourceRange();<br>
+          Diag(Member->getLocation(),<br>
+               diag::note_ref_or_ptr_member_declared_here)<br>
+              << (unsigned)AddressTaken;<br>
+        }<br>
+        break;<br>
+      }<br>
+<br>
+      case LK_New:<br>
+        break;<br>
+<br>
+      case LK_Return:<br>
+        // FIXME: Move -Wreturn-stack-address checks here.<br>
+        return false;<br>
+      }<br>
+      return false;<br>
+    }<br>
+<br>
+    auto *MTE = L.get<MaterializeTemporaryExpr*>();<br>
     switch (LK) {<br>
     case LK_FullExpression:<br>
       llvm_unreachable("already handled this");<br>
@@ -6520,11 +6608,11 @@ void Sema::checkInitializerLifetime(cons<br>
         // would be to clone the initializer expression on each use that would<br>
         // lifetime extend its temporaries.<br>
         Diag(MTE->getExprLoc(),<br>
-             EK == EK_ReferenceBinding<br>
+             RK == RK_ReferenceBinding<br>
                  ? diag::warn_default_member_init_temporary_not_extended<br>
                  : diag::warn_default_member_init_init_list_not_extended);<br>
       } else {<br>
-        llvm_unreachable("unexpected indirect temporary path");<br>
+        // FIXME: Warn on this.<br>
       }<br>
       break;<br>
<br>
@@ -6532,18 +6620,20 @@ void Sema::checkInitializerLifetime(cons<br>
       // Under C++ DR1696, if a mem-initializer (or a default member<br>
       // initializer used by the absence of one) would lifetime-extend a<br>
       // temporary, the program is ill-formed.<br>
-      if (auto *ExtendingDecl = ExtendingEntity->getDecl()) {<br>
+      if (auto *ExtendingDecl =<br>
+              ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {<br>
         bool IsSubobjectMember = ExtendingEntity != &Entity;<br>
         Diag(MTE->getExprLoc(), diag::err_bind_ref_member_to_temporary)<br>
             << ExtendingDecl << Init->getSourceRange() << IsSubobjectMember<br>
-            << EK;<br>
+            << RK;<br>
         // Don't bother adding a note pointing to the field if we're inside its<br>
         // default member initializer; our primary diagnostic points to the<br>
         // same place in that case.<br>
-        if (Path.empty() || !Path.back().is<CXXDefaultInitExpr*>()) {<br>
+        if (Path.empty() ||<br>
+            Path.back().Kind != IndirectLocalPathEntry::DefaultInit) {<br>
           Diag(ExtendingDecl->getLocation(),<br>
                diag::note_lifetime_extending_member_declared_here)<br>
-              << EK << IsSubobjectMember;<br>
+              << RK << IsSubobjectMember;<br>
         }<br>
       } else {<br>
         // We have a mem-initializer but no particular field within it; this<br>
@@ -6557,7 +6647,7 @@ void Sema::checkInitializerLifetime(cons<br>
       break;<br>
<br>
     case LK_New:<br>
-      if (EK == EK_ReferenceBinding) {<br>
+      if (RK == RK_ReferenceBinding) {<br>
         Diag(MTE->getExprLoc(), diag::warn_new_dangling_reference);<br>
       } else {<br>
         Diag(MTE->getExprLoc(), diag::warn_new_dangling_initializer_list)<br>
@@ -6573,9 +6663,14 @@ void Sema::checkInitializerLifetime(cons<br>
     // FIXME: Model these as CodeSynthesisContexts to fix the note emission<br>
     // order.<br>
     for (auto Elem : llvm::reverse(Path)) {<br>
-      if (auto *DIE = Elem.dyn_cast<CXXDefaultInitExpr*>()) {<br>
-        Diag(DIE->getExprLoc(), diag::note_in_default_member_initalizer_here)<br>
-            << DIE->getField();<br>
+      switch (Elem.Kind) {<br>
+      case IndirectLocalPathEntry::DefaultInit:<br>
+        Diag(Elem.E->getExprLoc(), diag::note_in_default_member_initalizer_here)<br>
+            << cast<CXXDefaultInitExpr>(Elem.E)->getField();<br>
+        break;<br>
+<br>
+      case IndirectLocalPathEntry::AddressOf:<br>
+        break;<br>
       }<br>
     }<br>
<br>
@@ -6584,12 +6679,12 @@ void Sema::checkInitializerLifetime(cons<br>
     return false;<br>
   };<br>
<br>
-  llvm::SmallVector<IndirectTemporaryPathEntry, 8> Path;<br>
+  llvm::SmallVector<IndirectLocalPathEntry, 8> Path;<br>
   if (Init->isGLValue())<br>
-    visitTemporariesExtendedByReferenceBinding(Path, Init, EK_ReferenceBinding,<br>
-                                               TemporaryVisitor);<br>
+    visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,<br>
+                                          TemporaryVisitor);<br>
   else<br>
-    visitTemporariesExtendedByInitializer(Path, Init, TemporaryVisitor);<br>
+    visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false);<br>
 }<br>
<br>
 static void DiagnoseNarrowingInInitList(Sema &S,<br>
@@ -6853,6 +6948,7 @@ InitializationSequence::Perform(Sema &S,<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>
@@ -7015,11 +7111,6 @@ InitializationSequence::Perform(Sema &S,<br>
         }<br>
       }<br>
<br>
-      // Even though we didn't materialize a temporary, the binding may still<br>
-      // extend the lifetime of a temporary. This happens if we bind a<br>
-      // reference to the result of a cast to reference type.<br>
-      S.checkInitializerLifetime(Entity, CurInit.get());<br>
-<br>
       CheckForNullPointerDereference(S, CurInit.get());<br>
       break;<br>
<br>
@@ -7036,10 +7127,6 @@ InitializationSequence::Perform(Sema &S,<br>
           Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType());<br>
       CurInit = MTE;<br>
<br>
-      // Maybe lifetime-extend the temporary's subobjects to match the<br>
-      // entity's lifetime.<br>
-      S.checkInitializerLifetime(Entity, CurInit.get());<br>
-<br>
       // If we're extending this temporary to automatic storage duration -- we<br>
       // need to register its cleanup during the full-expression's cleanups.<br>
       if (MTE->getStorageDuration() == SD_Automatic &&<br>
@@ -7490,10 +7577,6 @@ InitializationSequence::Perform(Sema &S,<br>
       // Wrap it in a construction of a std::initializer_list<T>.<br>
       CurInit = new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE);<br>
<br>
-      // Maybe lifetime-extend the array temporary's subobjects to match the<br>
-      // entity's lifetime.<br>
-      S.checkInitializerLifetime(Entity, CurInit.get());<br>
-<br>
       // Bind the result, in case the library has given initializer_list a<br>
       // non-trivial destructor.<br>
       if (shouldBindAsTemporary(Entity))<br>
@@ -7612,6 +7695,11 @@ InitializationSequence::Perform(Sema &S,<br>
     }<br>
   }<br>
<br>
+  // Check whether the initializer has a shorter lifetime than the initialized<br>
+  // entity, and if not, either lifetime-extend or warn as appropriate.<br>
+  if (auto *Init = CurInit.get())<br>
+    S.checkInitializerLifetime(Entity, Init);<br>
+<br>
   // Diagnose non-fatal problems with the completed initialization.<br>
   if (Entity.getKind() == InitializedEntity::EK_Member &&<br>
       cast<FieldDecl>(Entity.getDecl())->isBitField())<br>
<br>
Modified: cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp?rev=337627&r1=337626&r2=337627&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp?rev=337627&r1=337626&r2=337627&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp (original)<br>
+++ cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp Fri Jul 20 15:25:55 2018<br>
@@ -235,10 +235,10 @@ void fVoidPointerTest2() {<br>
 }<br>
<br>
 class VoidPointerRRefTest1 {<br>
-  void *&&vptrrref;<br>
+  void *&&vptrrref; // expected-note {{here}}<br>
<br>
 public:<br>
-  VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void *&&>(vptr)) {<br>
+  VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void *&&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to stack allocated parameter 'vptr'}}<br>
     // All good!<br>
   }<br>
 };<br>
@@ -249,10 +249,10 @@ void fVoidPointerRRefTest1() {<br>
 }<br>
<br>
 class VoidPointerRRefTest2 {<br>
-  void **&&vpptrrref;<br>
+  void **&&vpptrrref; // expected-note {{here}}<br>
<br>
 public:<br>
-  VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void **&&>(vptr)) {<br>
+  VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void **&&>(vptr)) { // expected-warning {{binding reference member 'vpptrrref' to stack allocated parameter 'vptr'}}<br>
     // All good!<br>
   }<br>
 };<br>
@@ -263,10 +263,10 @@ void fVoidPointerRRefTest2() {<br>
 }<br>
<br>
 class VoidPointerLRefTest {<br>
-  void *&vptrrref;<br>
+  void *&vptrrref; // expected-note {{here}}<br>
<br>
 public:<br>
-  VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void *&>(vptr)) {<br>
+  VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void *&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to stack allocated parameter 'vptr'}}<br>
     // All good!<br>
   }<br>
 };<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=337627&r1=337626&r2=337627&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=337627&r1=337626&r2=337627&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp Fri Jul 20 15:25:55 2018<br>
@@ -72,18 +72,18 @@ std::initializer_list<int> thread_local<br>
<br>
 // X86: @_ZN15partly_constant1kE = global i32 0, align 4<br>
 // X86: @_ZN15partly_constant2ilE = global {{.*}} null, align 8<br>
-// X86: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8<br>
-// X86: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8<br>
-// X86: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4<br>
-// X86: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4<br>
-// X86: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4<br>
+// X86: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE_]] = internal global {{.*}} zeroinitializer, align 8<br>
+// X86: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE0_]] = internal global [3 x {{.*}}] zeroinitializer, align 8<br>
+// X86: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE1_]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4<br>
+// X86: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE2_]] = internal global [2 x i32] zeroinitializer, align 4<br>
+// X86: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE3_]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4<br>
 // AMDGCN: @_ZN15partly_constant1kE = addrspace(1) global i32 0, align 4<br>
 // AMDGCN: @_ZN15partly_constant2ilE = addrspace(4) global {{.*}} null, align 8<br>
-// AMDGCN: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(4) global {{.*}} zeroinitializer, align 8<br>
-// AMDGCN: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(4) global [3 x {{.*}}] zeroinitializer, align 8<br>
-// AMDGCN: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal addrspace(4) constant [3 x i32] [i32 1, i32 2, i32 3], align 4<br>
-// AMDGCN: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal addrspace(4) global [2 x i32] zeroinitializer, align 4<br>
-// AMDGCN: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal addrspace(4) constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4<br>
+// AMDGCN: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE_]] = internal addrspace(4) global {{.*}} zeroinitializer, align 8<br>
+// AMDGCN: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE0_]] = internal addrspace(4) global [3 x {{.*}}] zeroinitializer, align 8<br>
+// AMDGCN: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE1_]] = internal addrspace(4) constant [3 x i32] [i32 1, i32 2, i32 3], align 4<br>
+// AMDGCN: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE2_]] = internal addrspace(4) global [2 x i32] zeroinitializer, align 4<br>
+// AMDGCN: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE3_]] = internal addrspace(4) constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4<br>
<br>
 // X86: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4<br>
 // X86: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4<br>
@@ -375,7 +375,7 @@ namespace partly_constant {<br>
   // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],<br>
   // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_THIRD]]{{.*}}, i64 0, i64 0),<br>
   // CHECK:       i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 2, i32 0)<br>
-  // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@_ZGRN15partly_constant2ilE4_{{.*}}, i64 0, i64 2, i32 1)<br>
+  // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 2, i32 1)<br>
   // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],<br>
   //<br>
   // Outer init list.<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><br clear="all"><div><br></div>-- <br><div dir="ltr" class="m_3187989672776187709gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Regards,</div><div>Ilya Biryukov</div></div></div></div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>Regards,</div><div>Ilya Biryukov</div></div></div></div></div>