r337329 - Restructure checking for, and warning on, lifetime extension.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 17 15:24:09 PDT 2018


Author: rsmith
Date: Tue Jul 17 15:24:09 2018
New Revision: 337329

URL: http://llvm.org/viewvc/llvm-project?rev=337329&view=rev
Log:
Restructure checking for, and warning on, lifetime extension.

This change implements C++ DR1696, which makes initialization of a
reference member of a class from a temporary object ill-formed. The
standard wording here is imprecise, but we interpret it as meaning that
any time a mem-initializer would result in lifetime extension, the
program is ill-formed.

This reinstates r337226, reverted in r337255, with a fix for the
InitializedEntity alignment problem that was breaking ARM buildbots.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/Analysis/initializer.cpp
    cfe/trunk/test/CXX/drs/dr16xx.cpp
    cfe/trunk/test/CXX/drs/dr18xx.cpp
    cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp
    cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp
    cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
    cfe/trunk/test/CXX/temp/temp.param/p5.cpp
    cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
    cfe/trunk/test/CodeGenCXX/temporaries.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/constexpr-default-arg.cpp
    cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
    cfe/trunk/test/SemaCXX/eval-crashes.cpp
    cfe/trunk/test/SemaCXX/member-init.cpp
    cfe/trunk/test/SemaCXX/warn-dangling-field.cpp
    cfe/trunk/www/cxx_dr_status.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Jul 17 15:24:09 2018
@@ -272,6 +272,7 @@ def ShiftOpParentheses: DiagGroup<"shift
 def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">;
 def DanglingElse: DiagGroup<"dangling-else">;
 def DanglingField : DiagGroup<"dangling-field">;
+def DanglingInitializerList : DiagGroup<"dangling-initializer-list">;
 def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
 def ExpansionToDefined : DiagGroup<"expansion-to-defined">;
 def FlagEnum : DiagGroup<"flag-enum">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jul 17 15:24:09 2018
@@ -2049,10 +2049,6 @@ def err_implied_std_initializer_list_not
   "not found; include <initializer_list>">;
 def err_malformed_std_initializer_list : Error<
   "std::initializer_list must be a class template with a single type parameter">;
-def warn_dangling_std_initializer_list : Warning<
-  "array backing the initializer list will be destroyed at the end of "
-  "%select{the full-expression|the constructor}0">,
-  InGroup<DiagGroup<"dangling-initializer-list">>;
 def err_auto_init_list_from_c : Error<
   "cannot use __auto_type with initializer list in C">;
 def err_auto_bitfield : Error<
@@ -7844,13 +7840,39 @@ def warn_bind_ref_member_to_parameter :
 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 %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">;
+
+def err_bind_ref_member_to_temporary : Error<
+  "%select{reference|backing array for 'std::initializer_list'}2 "
+  "%select{|subobject of }1member %0 "
+  "%select{binds to|is}2 a temporary object "
+  "whose lifetime would be shorter than the constructed object">;
+def note_lifetime_extending_member_declared_here : Note<
+  "%select{%select{reference|'std::initializer_list'}0 member|"
+  "member with %select{reference|'std::initializer_list'}0 subobject}1 "
+  "declared here">;
+def warn_new_dangling_reference : Warning<
+  "temporary bound to reference member of allocated object "
+  "will be destroyed at the end of the full-expression">,
+  InGroup<DanglingField>;
+def warn_new_dangling_initializer_list : Warning<
+  "array backing "
+  "%select{initializer list subobject of the allocated object|"
+  "the allocated initializer list}0 "
+  "will be destroyed at the end of the full-expression">,
+  InGroup<DanglingInitializerList>;
+def warn_default_member_init_temporary_not_extended : Warning<
+  "sorry, lifetime extension of temporary created by aggregate initialization "
+  "using default member initializer is not supported; lifetime of temporary "
+  "will end at the end of the full-expression">, InGroup<DanglingField>;
+def warn_default_member_init_init_list_not_extended : Warning<
+  "sorry, lifetime extension of backing array of initializer list "
+  "created by aggregate initialization using default member initializer "
+  "is not supported; lifetime of backing array will end at the end of the "
+  "full-expression">, InGroup<DanglingInitializerList>;
+def note_in_default_member_initalizer_here : Note<
+  "in default member initializer for field %0 used 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.

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Tue Jul 17 15:24:09 2018
@@ -46,7 +46,7 @@ class ObjCMethodDecl;
 class Sema;
 
 /// Describes an entity that is being initialized.
-class InitializedEntity {
+class alignas(8) InitializedEntity {
 public:
   /// Specifies the kind of entity being initialized.
   enum EntityKind {
@@ -63,7 +63,7 @@ public:
     /// is being thrown.
     EK_Exception,
 
-    /// The entity being initialized is a non-static data member 
+    /// The entity being initialized is a non-static data member
     /// subobject.
     EK_Member,
 
@@ -123,7 +123,7 @@ public:
     // enum as an index for its first %select.  When modifying this list,
     // that diagnostic text needs to be updated as well.
   };
-  
+
 private:
   /// The kind of entity being initialized.
   EntityKind Kind;
@@ -158,6 +158,10 @@ private:
     /// initialization in a copy or move constructor. These can perform array
     /// copies.
     bool IsImplicitFieldInit;
+
+    /// When Kind == EK_Member, whether this is the initial initialization
+    /// check for a default member initializer.
+    bool IsDefaultMemberInit;
   };
 
   struct C {
@@ -203,7 +207,7 @@ private:
 
   /// Create the initialization entity for a variable.
   InitializedEntity(VarDecl *Var, EntityKind EK = EK_Variable)
-      : Kind(EK), Type(Var->getType()), Variable{Var, false} {}
+      : Kind(EK), Type(Var->getType()), Variable{Var, false, false} {}
   
   /// Create the initialization entity for the result of a
   /// function, throwing an object, performing an explicit cast, or
@@ -217,9 +221,9 @@ private:
   
   /// Create the initialization entity for a member subobject.
   InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent,
-                    bool Implicit) 
+                    bool Implicit, bool DefaultMemberInit)
       : Kind(EK_Member), Parent(Parent), Type(Member->getType()),
-        Variable{Member, Implicit} {}
+        Variable{Member, Implicit, DefaultMemberInit} {}
   
   /// Create the initialization entity for an array element.
   InitializedEntity(ASTContext &Context, unsigned Index, 
@@ -339,21 +343,27 @@ public:
   static InitializedEntity InitializeDelegation(QualType Type) {
     return InitializedEntity(EK_Delegating, SourceLocation(), Type);
   }
-  
+
   /// Create the initialization entity for a member subobject.
   static InitializedEntity
   InitializeMember(FieldDecl *Member,
                    const InitializedEntity *Parent = nullptr,
                    bool Implicit = false) {
-    return InitializedEntity(Member, Parent, Implicit);
+    return InitializedEntity(Member, Parent, Implicit, false);
   }
-  
+
   /// Create the initialization entity for a member subobject.
   static InitializedEntity
   InitializeMember(IndirectFieldDecl *Member,
                    const InitializedEntity *Parent = nullptr,
                    bool Implicit = false) {
-    return InitializedEntity(Member->getAnonField(), Parent, Implicit);
+    return InitializedEntity(Member->getAnonField(), Parent, Implicit, false);
+  }
+
+  /// Create the initialization entity for a default member initializer.
+  static InitializedEntity
+  InitializeMemberFromDefaultMemberInitializer(FieldDecl *Member) {
+    return InitializedEntity(Member, nullptr, false, true);
   }
 
   /// Create the initialization entity for an array element.
@@ -453,6 +463,12 @@ public:
     return getKind() == EK_Member && Variable.IsImplicitFieldInit;
   }
 
+  /// Is this the default member initializer of a member (specified inside
+  /// the class definition)?
+  bool isDefaultMemberInitializer() const {
+    return getKind() == EK_Member && Variable.IsDefaultMemberInit;
+  }
+
   /// Determine the location of the 'return' keyword when initializing
   /// the result of a function call.
   SourceLocation getReturnLoc() const {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Jul 17 15:24:09 2018
@@ -2582,6 +2582,11 @@ public:
                                                  NamedDecl *FoundDecl,
                                                  CXXMethodDecl *Method);
 
+  /// Check that the lifetime of the initializer (and its subobjects) is
+  /// sufficient for initializing the entity, and perform lifetime extension
+  /// (when permitted) if not.
+  void checkInitializerLifetime(const InitializedEntity &Entity, Expr *Init);
+
   ExprResult PerformContextuallyConvertToBool(Expr *From);
   ExprResult PerformContextuallyConvertToObjCPointer(Expr *From);
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jul 17 15:24:09 2018
@@ -3621,7 +3621,8 @@ void Sema::ActOnFinishCXXInClassMemberIn
 
   ExprResult Init = InitExpr;
   if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
-    InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
+    InitializedEntity Entity =
+        InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD);
     InitializationKind Kind =
         FD->getInClassInitStyle() == ICIS_ListInit
             ? InitializationKind::CreateDirectList(InitExpr->getLocStart(),
@@ -4646,6 +4647,10 @@ static bool CollectFieldInitializer(Sema
         SemaRef.BuildCXXDefaultInitExpr(Info.Ctor->getLocation(), Field);
     if (DIE.isInvalid())
       return true;
+
+    auto Entity = InitializedEntity::InitializeMember(Field, nullptr, true);
+    SemaRef.checkInitializerLifetime(Entity, DIE.get());
+
     CXXCtorInitializer *Init;
     if (Indirect)
       Init = new (SemaRef.Context)

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Jul 17 15:24:09 2018
@@ -1864,13 +1864,6 @@ Sema::BuildCXXNew(SourceRange Range, boo
   if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
     return ExprError();
 
-  if (initStyle == CXXNewExpr::ListInit &&
-      isStdInitializerList(AllocType, nullptr)) {
-    Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(),
-         diag::warn_dangling_std_initializer_list)
-        << /*at end of FE*/0 << Inits[0]->getSourceRange();
-  }
-
   // In ARC, infer 'retaining' for the allocated
   if (getLangOpts().ObjCAutoRefCount &&
       AllocType.getObjCLifetime() == Qualifiers::OCL_None &&

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jul 17 15:24:09 2018
@@ -572,6 +572,7 @@ void InitListChecker::FillInEmptyInitFor
         hadError = true;
         return;
       }
+      SemaRef.checkInitializerLifetime(MemberEntity, DIE.get());
       if (Init < NumInits)
         ILE->setInit(Init, DIE.get());
       else {
@@ -6197,17 +6198,43 @@ InitializedEntityOutlivesFullExpression(
   llvm_unreachable("unknown entity kind");
 }
 
+namespace {
+enum LifetimeKind {
+  /// The lifetime of a temporary bound to this entity ends at the end of the
+  /// full-expression, and that's (probably) fine.
+  LK_FullExpression,
+
+  /// The lifetime of a temporary bound to this entity is extended to the
+  /// lifeitme of the entity itself.
+  LK_Extended,
+
+  /// The lifetime of a temporary bound to this entity probably ends too soon,
+  /// because the entity is allocated in a new-expression.
+  LK_New,
+
+  /// The lifetime of a temporary bound to this entity ends too soon, because
+  /// the entity is a return object.
+  LK_Return,
+
+  /// This is a mem-initializer: if it would extend a temporary (other than via
+  /// a default member initializer), the program is ill-formed.
+  LK_MemInitializer,
+};
+using LifetimeResult =
+    llvm::PointerIntPair<const InitializedEntity *, 3, LifetimeKind>;
+}
+
 /// Determine the declaration which an initialized entity ultimately refers to,
 /// for the purpose of lifetime-extending a temporary bound to a reference in
 /// the initialization of \p Entity.
-static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
+static LifetimeResult getEntityForTemporaryLifetimeExtension(
     const InitializedEntity *Entity,
-    const InitializedEntity *FallbackDecl = nullptr) {
+    const InitializedEntity *InitField = nullptr) {
   // C++11 [class.temporary]p5:
   switch (Entity->getKind()) {
   case InitializedEntity::EK_Variable:
     //   The temporary [...] persists for the lifetime of the reference
-    return Entity;
+    return {Entity, LK_Extended};
 
   case InitializedEntity::EK_Member:
     // For subobjects, we look at the complete object.
@@ -6216,29 +6243,43 @@ static const InitializedEntity *getEntit
                                                     Entity);
 
     //   except:
-    //   -- A temporary bound to a reference member in a constructor's
-    //      ctor-initializer persists until the constructor exits.
-    return Entity;
+    // C++17 [class.base.init]p8:
+    //   A temporary expression bound to a reference member in a
+    //   mem-initializer is ill-formed.
+    // C++17 [class.base.init]p11:
+    //   A temporary expression bound to a reference member from a
+    //   default member initializer is ill-formed.
+    //
+    // The context of p11 and its example suggest that it's only the use of a
+    // default member initializer from a constructor that makes the program
+    // ill-formed, not its mere existence, and that it can even be used by
+    // aggregate initialization.
+    return {Entity, Entity->isDefaultMemberInitializer() ? LK_Extended
+                                                         : LK_MemInitializer};
 
   case InitializedEntity::EK_Binding:
     // Per [dcl.decomp]p3, the binding is treated as a variable of reference
     // type.
-    return Entity;
+    return {Entity, LK_Extended};
 
   case InitializedEntity::EK_Parameter:
   case InitializedEntity::EK_Parameter_CF_Audited:
     //   -- A temporary bound to a reference parameter in a function call
     //      persists until the completion of the full-expression containing
     //      the call.
+    return {nullptr, LK_FullExpression};
+
   case InitializedEntity::EK_Result:
     //   -- The lifetime of a temporary bound to the returned value in a
     //      function return statement is not extended; the temporary is
     //      destroyed at the end of the full-expression in the return statement.
+    return {nullptr, LK_Return};
+
   case InitializedEntity::EK_New:
     //   -- A temporary bound to a reference in a new-initializer persists
     //      until the completion of the full-expression containing the
     //      new-initializer.
-    return nullptr;
+    return {nullptr, LK_New};
 
   case InitializedEntity::EK_Temporary:
   case InitializedEntity::EK_CompoundLiteralInit:
@@ -6246,25 +6287,26 @@ static const InitializedEntity *getEntit
     // We don't yet know the storage duration of the surrounding temporary.
     // Assume it's got full-expression duration for now, it will patch up our
     // storage duration if that's not correct.
-    return nullptr;
+    return {nullptr, LK_FullExpression};
 
   case InitializedEntity::EK_ArrayElement:
     // For subobjects, we look at the complete object.
     return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
-                                                  FallbackDecl);
+                                                  InitField);
 
   case InitializedEntity::EK_Base:
     // For subobjects, we look at the complete object.
     if (Entity->getParent())
       return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
-                                                    Entity);
-    LLVM_FALLTHROUGH;
+                                                    InitField);
+    return {InitField, LK_MemInitializer};
+
   case InitializedEntity::EK_Delegating:
     // We can reach this case for aggregate initialization in a constructor:
     //   struct A { int &&r; };
     //   struct B : A { B() : A{0} {} };
-    // In this case, use the innermost field decl as the context.
-    return FallbackDecl;
+    // In this case, use the outermost field decl as the context.
+    return {InitField, LK_MemInitializer};
 
   case InitializedEntity::EK_BlockElement:
   case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
@@ -6272,30 +6314,54 @@ static const InitializedEntity *getEntit
   case InitializedEntity::EK_Exception:
   case InitializedEntity::EK_VectorElement:
   case InitializedEntity::EK_ComplexElement:
-    return nullptr;
+    return {nullptr, LK_FullExpression};
   }
   llvm_unreachable("unknown entity kind");
 }
 
-static void performLifetimeExtension(Expr *Init,
-                                     const InitializedEntity *ExtendingEntity);
+namespace {
+enum ExtensionKind {
+  /// Lifetime would be extended by a reference binding to a temporary.
+  EK_ReferenceBinding,
+  /// Lifetime would be extended by a std::initializer_list object binding to
+  /// its backing array.
+  EK_StdInitializerList,
+};
+using IndirectTemporaryPathEntry =
+    llvm::PointerUnion<CXXDefaultInitExpr *, ValueDecl *>;
+using IndirectTemporaryPath = llvm::SmallVectorImpl<IndirectTemporaryPathEntry>;
+
+struct RevertToOldSizeRAII {
+  IndirectTemporaryPath &Path;
+  unsigned OldSize = Path.size();
+  RevertToOldSizeRAII(IndirectTemporaryPath &Path) : Path(Path) {}
+  ~RevertToOldSizeRAII() { Path.resize(OldSize); }
+};
+}
+
+template <typename TemporaryVisitor>
+static void visitTemporariesExtendedByInitializer(IndirectTemporaryPath &Path,
+                                                  Expr *Init,
+                                                  TemporaryVisitor Visit);
+
+/// Visit the temporaries whose lifetimes would be extended by binding a
+/// reference to the glvalue expression \c Init.
+template <typename TemporaryVisitor>
+static void
+visitTemporariesExtendedByReferenceBinding(IndirectTemporaryPath &Path,
+                                           Expr *Init, ExtensionKind EK,
+                                           TemporaryVisitor Visit) {
+  RevertToOldSizeRAII RAII(Path);
 
-/// Update a glvalue expression that is used as the initializer of a reference
-/// to note that its lifetime is extended.
-/// \return \c true if any temporary had its lifetime extended.
-static bool
-performReferenceExtension(Expr *Init,
-                          const InitializedEntity *ExtendingEntity) {
   // Walk past any constructs which we can lifetime-extend across.
   Expr *Old;
   do {
     Old = Init;
 
     if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
-      if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
-        // This is just redundant braces around an initializer. Step over it.
+      // If this is just redundant braces around an initializer, step over it.
+      if (ILE->isTransparent())
         Init = ILE->getInit(0);
-      }
     }
 
     // Step over any subobject adjustments; we may have a materialized
@@ -6312,40 +6378,65 @@ performReferenceExtension(Expr *Init,
     // when performing lifetime extension.
     if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init))
       Init = ASE->getBase();
+
+    // Step into CXXDefaultInitExprs so we can diagnose cases where a
+    // constructor inherits one as an implicit mem-initializer.
+    if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
+      Path.push_back(DIE);
+      Init = DIE->getExpr();
+
+      if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+        Init = EWC->getSubExpr();
+    }
   } while (Init != Old);
 
-  if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {
-    // Update the storage duration of the materialized temporary.
-    // FIXME: Rebuild the expression instead of mutating it.
-    ME->setExtendingDecl(ExtendingEntity->getDecl(),
-                         ExtendingEntity->allocateManglingNumber());
-    performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingEntity);
-    return true;
+  if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
+    if (Visit(Path, MTE, EK))
+      visitTemporariesExtendedByInitializer(Path, MTE->GetTemporaryExpr(),
+                                            Visit);
   }
-
-  return false;
 }
 
-/// Update a prvalue expression that is going to be materialized as a
-/// lifetime-extended temporary.
-static void performLifetimeExtension(Expr *Init,
-                                     const InitializedEntity *ExtendingEntity) {
+/// Visit the temporaries whose lifetimes would be extended by
+/// lifetime-extending the object initialized by the prvalue expression \c
+/// Init.
+template <typename TemporaryVisitor>
+static void visitTemporariesExtendedByInitializer(IndirectTemporaryPath &Path,
+                                                  Expr *Init,
+                                                  TemporaryVisitor Visit) {
+  RevertToOldSizeRAII RAII(Path);
+
+  // Step into CXXDefaultInitExprs so we can diagnose cases where a
+  // constructor inherits one as an implicit mem-initializer.
+  if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
+    Path.push_back(DIE);
+    Init = DIE->getExpr();
+
+    if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+      Init = EWC->getSubExpr();
+  }
+
   // Dig out the expression which constructs the extended temporary.
   Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
 
   if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
     Init = BTE->getSubExpr();
 
-  if (CXXStdInitializerListExpr *ILE =
-          dyn_cast<CXXStdInitializerListExpr>(Init)) {
-    performReferenceExtension(ILE->getSubExpr(), ExtendingEntity);
-    return;
-  }
+  // C++17 [dcl.init.list]p6:
+  //   initializing an initializer_list object from the array extends the
+  //   lifetime of the array exactly like binding a reference to a temporary.
+  if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))
+    return visitTemporariesExtendedByReferenceBinding(
+        Path, ILE->getSubExpr(), EK_StdInitializerList, Visit);
 
   if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+    if (ILE->isTransparent())
+      return visitTemporariesExtendedByInitializer(Path, ILE->getInit(0),
+                                                   Visit);
+
     if (ILE->getType()->isArrayType()) {
       for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
-        performLifetimeExtension(ILE->getInit(I), ExtendingEntity);
+        visitTemporariesExtendedByInitializer(Path, ILE->getInit(I), Visit);
       return;
     }
 
@@ -6357,7 +6448,8 @@ static void performLifetimeExtension(Exp
       // bound to temporaries, those temporaries are also lifetime-extended.
       if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
           ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
-        performReferenceExtension(ILE->getInit(0), ExtendingEntity);
+        visitTemporariesExtendedByReferenceBinding(Path, ILE->getInit(0),
+                                                   EK_ReferenceBinding, Visit);
       else {
         unsigned Index = 0;
         for (const auto *I : RD->fields()) {
@@ -6367,13 +6459,13 @@ static void performLifetimeExtension(Exp
             continue;
           Expr *SubInit = ILE->getInit(Index);
           if (I->getType()->isReferenceType())
-            performReferenceExtension(SubInit, ExtendingEntity);
-          else if (isa<InitListExpr>(SubInit) ||
-                   isa<CXXStdInitializerListExpr>(SubInit))
-            // This may be either aggregate-initialization of a member or
-            // initialization of a std::initializer_list object. Either way,
+            visitTemporariesExtendedByReferenceBinding(
+                Path, SubInit, EK_ReferenceBinding, Visit);
+          else
+            // This might be either aggregate-initialization of a member or
+            // initialization of a std::initializer_list object. Regardless,
             // we should recursively lifetime-extend that initializer.
-            performLifetimeExtension(SubInit, ExtendingEntity);
+            visitTemporariesExtendedByInitializer(Path, SubInit, Visit);
           ++Index;
         }
       }
@@ -6381,37 +6473,123 @@ static void performLifetimeExtension(Exp
   }
 }
 
-static void warnOnLifetimeExtension(Sema &S, const InitializedEntity &Entity,
-                                    const Expr *Init, bool IsInitializerList,
-                                    const ValueDecl *ExtendingDecl) {
-  // Warn if a field lifetime-extends a temporary.
-  if (isa<FieldDecl>(ExtendingDecl)) {
-    if (IsInitializerList) {
-      S.Diag(Init->getExprLoc(), diag::warn_dangling_std_initializer_list)
-        << /*at end of constructor*/true;
-      return;
+/// Determine whether this is an indirect path to a temporary that we are
+/// supposed to lifetime-extend along (but don't).
+static bool shouldLifetimeExtendThroughPath(const IndirectTemporaryPath &Path) {
+  for (auto Elem : Path) {
+    if (!Elem.is<CXXDefaultInitExpr*>())
+      return false;
+  }
+  return true;
+}
+
+void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
+                                    Expr *Init) {
+  LifetimeResult LR = getEntityForTemporaryLifetimeExtension(&Entity);
+  LifetimeKind LK = LR.getInt();
+  const InitializedEntity *ExtendingEntity = LR.getPointer();
+
+  // If this entity doesn't have an interesting lifetime, don't bother looking
+  // for temporaries within its initializer.
+  if (LK == LK_FullExpression)
+    return;
+
+  auto TemporaryVisitor = [&](IndirectTemporaryPath &Path,
+                              MaterializeTemporaryExpr *MTE,
+                              ExtensionKind EK) -> bool {
+    switch (LK) {
+    case LK_FullExpression:
+      llvm_unreachable("already handled this");
+
+    case LK_Extended:
+      // Lifetime-extend the temporary.
+      if (Path.empty()) {
+        // Update the storage duration of the materialized temporary.
+        // FIXME: Rebuild the expression instead of mutating it.
+        MTE->setExtendingDecl(ExtendingEntity->getDecl(),
+                              ExtendingEntity->allocateManglingNumber());
+        // Also visit the temporaries lifetime-extended by this initializer.
+        return true;
+      }
+
+      if (shouldLifetimeExtendThroughPath(Path)) {
+        // We're supposed to lifetime-extend the temporary along this path (per
+        // the resolution of DR1815), but we don't support that yet.
+        //
+        // FIXME: Properly handle this situation. Perhaps the easiest approach
+        // would be to clone the initializer expression on each use that would
+        // lifetime extend its temporaries.
+        Diag(MTE->getExprLoc(),
+             EK == EK_ReferenceBinding
+                 ? diag::warn_default_member_init_temporary_not_extended
+                 : diag::warn_default_member_init_init_list_not_extended);
+      } else {
+        llvm_unreachable("unexpected indirect temporary path");
+      }
+      break;
+
+    case LK_MemInitializer:
+      // Under C++ DR1696, if a mem-initializer (or a default member
+      // initializer used by the absence of one) would lifetime-extend a
+      // temporary, the program is ill-formed.
+      if (auto *ExtendingDecl = ExtendingEntity->getDecl()) {
+        bool IsSubobjectMember = ExtendingEntity != &Entity;
+        Diag(MTE->getExprLoc(), diag::err_bind_ref_member_to_temporary)
+            << ExtendingDecl << Init->getSourceRange() << IsSubobjectMember
+            << EK;
+        // Don't bother adding a note pointing to the field if we're inside its
+        // default member initializer; our primary diagnostic points to the
+        // same place in that case.
+        if (Path.empty() || !Path.back().is<CXXDefaultInitExpr*>()) {
+          Diag(ExtendingDecl->getLocation(),
+               diag::note_lifetime_extending_member_declared_here)
+              << EK << IsSubobjectMember;
+        }
+      } else {
+        // We have a mem-initializer but no particular field within it; this
+        // is either a base class or a delegating initializer directly
+        // initializing the base-class from something that doesn't live long
+        // enough. Either way, that can't happen.
+        // FIXME: Move CheckForDanglingReferenceOrPointer checks here.
+        llvm_unreachable(
+            "temporary initializer for base class / delegating ctor");
+      }
+      break;
+
+    case LK_New:
+      if (EK == EK_ReferenceBinding) {
+        Diag(MTE->getExprLoc(), diag::warn_new_dangling_reference);
+      } else {
+        Diag(MTE->getExprLoc(), diag::warn_new_dangling_initializer_list)
+            << (ExtendingEntity != &Entity);
+      }
+      break;
+
+    case LK_Return:
+      // FIXME: Move -Wreturn-stack-address checks here.
+      return false;
     }
 
-    bool IsSubobjectMember = false;
-    for (const InitializedEntity *Ent = Entity.getParent(); Ent;
-         Ent = Ent->getParent()) {
-      if (Ent->getKind() != InitializedEntity::EK_Base) {
-        IsSubobjectMember = true;
-        break;
+    // FIXME: Model these as CodeSynthesisContexts to fix the note emission
+    // order.
+    for (auto Elem : llvm::reverse(Path)) {
+      if (auto *DIE = Elem.dyn_cast<CXXDefaultInitExpr*>()) {
+        Diag(DIE->getExprLoc(), diag::note_in_default_member_initalizer_here)
+            << DIE->getField();
       }
     }
-    S.Diag(Init->getExprLoc(),
-           diag::warn_bind_ref_member_to_temporary)
-      << ExtendingDecl << Init->getSourceRange()
-      << IsSubobjectMember << IsInitializerList;
-    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)
-        << /*is pointer*/false;
-  }
+
+    // We didn't lifetime-extend, so don't go any further; we don't need more
+    // warnings or errors on inner temporaries within this one's initializer.
+    return false;
+  };
+
+  llvm::SmallVector<IndirectTemporaryPathEntry, 8> Path;
+  if (Init->isGLValue())
+    visitTemporariesExtendedByReferenceBinding(Path, Init, EK_ReferenceBinding,
+                                               TemporaryVisitor);
+  else
+    visitTemporariesExtendedByInitializer(Path, Init, TemporaryVisitor);
 }
 
 static void DiagnoseNarrowingInInitList(Sema &S,
@@ -6838,14 +7016,9 @@ InitializationSequence::Perform(Sema &S,
       }
 
       // Even though we didn't materialize a temporary, the binding may still
-      // extend the lifetime of a temporary. This happens if we bind a reference
-      // to the result of a cast to reference type.
-      if (const InitializedEntity *ExtendingEntity =
-              getEntityForTemporaryLifetimeExtension(&Entity))
-        if (performReferenceExtension(CurInit.get(), ExtendingEntity))
-          warnOnLifetimeExtension(S, Entity, CurInit.get(),
-                                  /*IsInitializerList=*/false,
-                                  ExtendingEntity->getDecl());
+      // extend the lifetime of a temporary. This happens if we bind a
+      // reference to the result of a cast to reference type.
+      S.checkInitializerLifetime(Entity, CurInit.get());
 
       CheckForNullPointerDereference(S, CurInit.get());
       break;
@@ -6861,23 +7034,17 @@ InitializationSequence::Perform(Sema &S,
       // Materialize the temporary into memory.
       MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
           Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType());
+      CurInit = MTE;
 
       // Maybe lifetime-extend the temporary's subobjects to match the
       // entity's lifetime.
-      if (const InitializedEntity *ExtendingEntity =
-              getEntityForTemporaryLifetimeExtension(&Entity))
-        if (performReferenceExtension(MTE, ExtendingEntity))
-          warnOnLifetimeExtension(S, Entity, CurInit.get(),
-                                  /*IsInitializerList=*/false,
-                                  ExtendingEntity->getDecl());
+      S.checkInitializerLifetime(Entity, CurInit.get());
 
       // If we're extending this temporary to automatic storage duration -- we
       // need to register its cleanup during the full-expression's cleanups.
       if (MTE->getStorageDuration() == SD_Automatic &&
           MTE->getType().isDestructedType())
         S.Cleanup.setExprNeedsCleanups(true);
-
-      CurInit = MTE;
       break;
     }
 
@@ -7320,18 +7487,13 @@ InitializationSequence::Perform(Sema &S,
           CurInit.get()->getType(), CurInit.get(),
           /*BoundToLvalueReference=*/false);
 
-      // Maybe lifetime-extend the array temporary's subobjects to match the
-      // entity's lifetime.
-      if (const InitializedEntity *ExtendingEntity =
-              getEntityForTemporaryLifetimeExtension(&Entity))
-        if (performReferenceExtension(MTE, ExtendingEntity))
-          warnOnLifetimeExtension(S, Entity, CurInit.get(),
-                                  /*IsInitializerList=*/true,
-                                  ExtendingEntity->getDecl());
-
       // Wrap it in a construction of a std::initializer_list<T>.
       CurInit = new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE);
 
+      // Maybe lifetime-extend the array temporary's subobjects to match the
+      // entity's lifetime.
+      S.checkInitializerLifetime(Entity, CurInit.get());
+
       // Bind the result, in case the library has given initializer_list a
       // non-trivial destructor.
       if (shouldBindAsTemporary(Entity))

Modified: cfe/trunk/test/Analysis/initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/initializer.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/initializer.cpp (original)
+++ cfe/trunk/test/Analysis/initializer.cpp Tue Jul 17 15:24:09 2018
@@ -178,29 +178,6 @@ namespace ReferenceInitialization {
     const MyStruct &myStruct(OtherStruct(5));
     myStruct.method(); // no-warning
   }
-
-  struct HasMyStruct {
-    const MyStruct &ms; // expected-note {{reference member declared here}}
-    const MyStruct &msWithCleanups; // expected-note {{reference member declared here}}
-
-    // clang's Sema issues a warning when binding a reference member to a
-    // temporary value.
-    HasMyStruct() : ms(5), msWithCleanups(OtherStruct(5)) {
-        // expected-warning at -1 {{binding reference member 'ms' to a temporary value}}
-        // expected-warning at -2 {{binding reference member 'msWithCleanups' to a temporary value}}
-
-      // At this point the members are not garbage so we should not expect an
-      // analyzer warning here even though binding a reference member
-      // to a member is a terrible idea.
-      ms.method(); // no-warning
-      msWithCleanups.method(); // no-warning
-    }
-  };
-
-  void referenceInitializeField() {
-    HasMyStruct hms;
-  }
-
 };
 
 namespace PR31592 {

Modified: cfe/trunk/test/CXX/drs/dr16xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr16xx.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr16xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr16xx.cpp Tue Jul 17 15:24:09 2018
@@ -9,6 +9,20 @@
 #define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
 #endif
 
+#if __cplusplus >= 201103L
+namespace std {
+  typedef decltype(sizeof(int)) size_t;
+
+  template<typename E> class initializer_list {
+    const E *begin;
+    size_t size;
+
+  public:
+    initializer_list();
+  };
+} // std
+#endif
+
 namespace dr1611 { // dr1611: dup 1658
   struct A { A(int); };
   struct B : virtual A { virtual void f() = 0; };
@@ -269,3 +283,83 @@ namespace dr1687 { // dr1687: 7
   auto c = To<E1>() <=> To<E2>(); // expected-error {{invalid operands to binary expression ('To<dr1687::E1>' and 'To<dr1687::E2>')}}
 #endif
 }
+
+namespace dr1696 { // dr1696: 7
+  namespace std_examples {
+#if __cplusplus >= 201402L
+    extern struct A a;
+    struct A {
+      const A &x = { A{a, a} };
+      const A &y = { A{} }; // expected-error {{default member initializer for 'y' needed within definition of enclosing class 'A' outside of member functions}} expected-note {{here}}
+    };
+    A a{a, a};
+#endif
+  }
+
+  struct A { A(); ~A(); };
+#if __cplusplus >= 201103L
+  struct B {
+    A &&a; // expected-note {{declared here}}
+    B() : a{} {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the constructed object}}
+  } b;
+#endif
+
+  struct C {
+    C();
+    const A &a; // expected-note {{declared here}}
+  };
+  C::C() : a(A()) {} // expected-error {{reference member 'a' binds to a temporary object whose lifetime would be shorter than the constructed object}}
+
+#if __cplusplus >= 201103L
+  // This is OK in C++14 onwards, per DR1815, though we don't support that yet:
+  //   D1 d1 = {};
+  // is equivalent to
+  //   D1 d1 = {A()};
+  // ... which lifetime-extends the A temporary.
+  struct D1 {
+    const A &a = A();
+#if __cplusplus < 201402L
+    // expected-error at -2 {{binds to a temporary}}
+    // expected-note at -4 {{here}}
+#else
+    // expected-warning-re at -5 {{sorry, lifetime extension {{.*}} not supported}}
+#endif
+  };
+  D1 d1 = {}; // expected-note {{here}}
+
+  struct D2 {
+    const A &a = A(); // expected-error {{binds to a temporary}}
+    D2() {} // expected-note {{used here}}
+  };
+
+  struct D3 { // expected-note {{used here}}
+    const A &a = A(); // expected-error {{binds to a temporary}}
+  };
+  D3 d3; // expected-note {{first required here}}
+
+  struct haslist1 {
+    std::initializer_list<int> il; // expected-note {{'std::initializer_list' member}}
+    haslist1(int i) : il{i, 2, 3} {} // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+  };
+
+  struct haslist2 {
+    std::initializer_list<int> il; // expected-note {{'std::initializer_list' member}}
+    haslist2();
+  };
+  haslist2::haslist2() : il{1, 2} {} // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+
+  struct haslist3 {
+    std::initializer_list<int> il = {1, 2, 3};
+  };
+
+  struct haslist4 { // expected-note {{in default member initializer}}
+    std::initializer_list<int> il = {1, 2, 3}; // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+  };
+  haslist4 hl4; // expected-note {{in implicit default constructor}}
+
+  struct haslist5 {
+    std::initializer_list<int> il = {1, 2, 3}; // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+    haslist5() {} // expected-note {{in default member initializer}}
+  };
+#endif
+}

Modified: cfe/trunk/test/CXX/drs/dr18xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr18xx.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr18xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr18xx.cpp Tue Jul 17 15:24:09 2018
@@ -30,6 +30,17 @@ namespace dr1813 { // dr1813: 7
   static_assert(!__is_standard_layout(U), "");
 }
 
+namespace dr1815 { // dr1815: no
+#if __cplusplus >= 201402L
+  // FIXME: needs codegen test
+  struct A { int &&r = 0; }; // FIXME expected-warning {{not supported}}
+  A a = {}; // expected-note {{here}}
+
+  struct B { int &&r = 0; }; // expected-error {{binds to a temporary}} expected-note {{here}}
+  B b; // expected-note {{here}}
+#endif
+}
+
 namespace dr1881 { // dr1881: 7
   struct A { int a : 4; };
   struct B : A { int b : 3; };

Modified: cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/p11.0x.copy.cpp Tue Jul 17 15:24:09 2018
@@ -121,13 +121,22 @@ extern HasNoAccessDtorBase HNADBa;
 HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}}
 
 // -- a non-static data member of rvalue reference type
+int some_int;
 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 at -1{{binding reference member 'ri' to a temporary}} expected-note at -1 {{here}}
+  int && ri = static_cast<int&&>(some_int); // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
 };
 RValue RVa;
 RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}}
 
+// FIXME: The note on the class-name is attached to the location of the
+// constructor. This is not especially clear.
+struct RValueTmp { // expected-note {{used here}}
+  int && ri = 1; // expected-note{{copy constructor of 'RValueTmp' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
+  // expected-error at -1 {{reference member 'ri' binds to a temporary}}
+};
+RValueTmp RVTa; // expected-note {{implicit default constructor for 'RValueTmp' first required here}}
+RValueTmp RVTb(RVTa); // expected-error{{call to implicitly-deleted copy constructor}}
+
 namespace PR13381 {
   struct S {
     S(const S&);

Modified: cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/p11.0x.move.cpp Tue Jul 17 15:24:09 2018
@@ -145,7 +145,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // e
 // The restriction on rvalue reference members applies to only the copy
 // constructor.
 struct RValue {
-  int &&ri = 1; // expected-warning {{binding reference member 'ri' to a temporary}} expected-note {{here}}
+  int &&ri = 1;
   RValue(RValue&&);
 };
 RValue::RValue(RValue&&) = default;

Modified: cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.ctor/p5-0x.cpp Tue Jul 17 15:24:09 2018
@@ -43,8 +43,12 @@ class NotDeleted2a { int &a = n; };
 NotDeleted2a nd2a;
 class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
 NotDeleted2b nd2b;
-class NotDeleted2c { int &&a = 0; }; // expected-warning {{binding reference member 'a' to a temporary}} expected-note {{here}}
+class NotDeleted2c { int &&a = static_cast<int&&>(n); };
 NotDeleted2c nd2c;
+// Note: this one does not have a deleted default constructor even though the
+// implicit default constructor is ill-formed!
+class NotDeleted2d { int &&a = 0; }; // expected-error {{reference member 'a' binds to a temporary object}} expected-note {{here}}
+NotDeleted2d nd2d; // expected-note {{first required here}}
 
 // - any non-variant non-static data member of const qualified type (or array
 // thereof) with no brace-or-equal-initializer does not have a user-provided

Modified: cfe/trunk/test/CXX/temp/temp.param/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p5.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.param/p5.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.param/p5.cpp Tue Jul 17 15:24:09 2018
@@ -1,13 +1,13 @@
 // RUN: %clang_cc1 -verify %s -std=c++14
 
-template<const int I> struct S {
+template<const int I> struct S { // expected-note {{in default member initializer}}
   decltype(I) n;
-  int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
+  int &&r = I; // expected-error {{reference member 'r' binds to a temporary object}}
 };
-S<5> s; // expected-note {{instantiation}}
+S<5> s; // expected-note {{implicit default constructor}}
 
-template<typename T, T v> struct U {
+template<typename T, T v> struct U { // expected-note {{in default member initializer}}
   decltype(v) n;
-  int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
+  int &&r = v; // expected-error {{reference member 'r' binds to a temporary object}}
 };
-U<const int, 6> u; // expected-note {{instantiation}}
+U<const int, 6> u; // expected-note {{implicit default constructor}}

Modified: cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp Tue Jul 17 15:24:09 2018
@@ -236,36 +236,6 @@ void fn9() {
   // CHECK: ret void
 }
 
-struct haslist1 {
-  std::initializer_list<int> il;
-  haslist1(int i);
-};
-
-// CHECK-LABEL: define void @_ZN8haslist1C2Ei
-haslist1::haslist1(int i)
-// CHECK: alloca [3 x i32]
-// CHECK: store i32 %
-// CHECK: store i32 2
-// CHECK: store i32 3
-  : il{i, 2, 3}
-{
-  destroyme2 dm2;
-}
-
-struct haslist2 {
-  std::initializer_list<destroyme1> il;
-  haslist2();
-};
-
-// CHECK-LABEL: define void @_ZN8haslist2C2Ev
-haslist2::haslist2()
-  : il{destroyme1(), destroyme1()}
-{
-  destroyme2 dm2;
-  // CHECK: call void @_ZN10destroyme2D1Ev
-  // CHECK: call void @_ZN10destroyme1D1Ev
-}
-
 void fn10(int i) {
   // CHECK-LABEL: define void @_Z4fn10i
   // CHECK: alloca [3 x i32]

Modified: cfe/trunk/test/CodeGenCXX/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/temporaries.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/temporaries.cpp Tue Jul 17 15:24:09 2018
@@ -198,20 +198,6 @@ B::B()
   f();
 }
   
-struct C {
-  C();
-  
-  const B& b;
-};
-
-C::C() 
-  // CHECK: call void @_ZN6PR50771BC1Ev
-  : b(B()) {
-  // CHECK: call void @_ZN6PR50771fEv
-  f();
-  
-  // CHECK: call void @_ZN6PR50771BD1Ev
-}
 }
 
 A f8() {
@@ -816,16 +802,3 @@ namespace PR14130 {
   // CHECK: call void @_ZN7PR141301SC1Ei({{.*}} @_ZGRN7PR141301vE_, i32 0)
   // CHECK: store {{.*}} @_ZGRN7PR141301vE_, {{.*}} @_ZN7PR141301vE
 }
-
-namespace Ctor {
-  struct A { A(); ~A(); };
-  void f();
-  struct B {
-    A &&a;
-    B() : a{} { f(); }
-  } b;
-  // CHECK: define {{.*}}void @_ZN4Ctor1BC1Ev(
-  // CHECK: call void @_ZN4Ctor1AC1Ev(
-  // CHECK: call void @_ZN4Ctor1fEv(
-  // CHECK: call void @_ZN4Ctor1AD1Ev(
-}

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Jul 17 15:24:09 2018
@@ -1892,14 +1892,15 @@ namespace Lifetime {
   }
 
   constexpr int &get(int &&n) { return n; }
+  constexpr int &&get_rv(int &&n) { return static_cast<int&&>(n); }
   struct S {
-    int &&r; // expected-note 2{{declared here}}
+    int &&r;
     int &s;
     int t;
-    constexpr S() : r(0), s(get(0)), t(r) {} // expected-warning {{temporary}}
-    constexpr S(int) : r(0), s(get(0)), t(s) {} // expected-warning {{temporary}} expected-note {{read of object outside its lifetime}}
+    constexpr S() : r(get_rv(0)), s(get(0)), t(r) {} // expected-note {{read of object outside its lifetime}}
+    constexpr S(int) : r(get_rv(0)), s(get(0)), t(s) {} // expected-note {{read of object outside its lifetime}}
   };
-  constexpr int k1 = S().t; // ok, int is lifetime-extended to end of constructor
+  constexpr int k1 = S().t; // expected-error {{constant expression}} expected-note {{in call}}
   constexpr int k2 = S(0).t; // expected-error {{constant expression}} expected-note {{in call}}
 }
 

Modified: cfe/trunk/test/SemaCXX/constexpr-default-arg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-default-arg.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-default-arg.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-default-arg.cpp Tue Jul 17 15:24:09 2018
@@ -31,8 +31,8 @@ void test_default_arg2() {
 }
 
 // Check that multiple CXXDefaultInitExprs don't cause an assertion failure.
-struct A { int &&r = 0; }; // expected-warning {{binding reference member}} // expected-note {{reference member declared here}}
+struct A { int &&r = 0; }; // expected-warning 2{{not supported}}
 struct B { A x, y; };
-B b = {};
+B b = {}; // expected-note 2{{in default member initializer for field 'r' used here}}
 
 }

Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp Tue Jul 17 15:24:09 2018
@@ -153,13 +153,14 @@ void dangle() {
 }
 
 struct haslist1 {
-  std::initializer_list<int> il = {1, 2, 3}; // expected-warning{{at the end of the constructor}}
-  std::initializer_list<int> jl{1, 2, 3}; // expected-warning{{at the end of the constructor}}
+  std::initializer_list<int> il // expected-note {{declared here}}
+    = {1, 2, 3}; // ok, unused
+  std::initializer_list<int> jl{1, 2, 3}; // expected-error {{backing array for 'std::initializer_list' member 'jl' is a temporary object}}
   haslist1();
 };
 
-haslist1::haslist1()
-: il{1, 2, 3} // expected-warning{{at the end of the constructor}}
+haslist1::haslist1() // expected-note {{used here}}
+: il{1, 2, 3} // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
 {}
 
 namespace PR12119 {

Modified: cfe/trunk/test/SemaCXX/eval-crashes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/eval-crashes.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/eval-crashes.cpp (original)
+++ cfe/trunk/test/SemaCXX/eval-crashes.cpp Tue Jul 17 15:24:09 2018
@@ -26,10 +26,10 @@ namespace pr33140_0b {
 
 namespace pr33140_2 {
   // FIXME: The declaration of 'b' below should lifetime-extend two int
-  // temporaries, invalidating this warning to some extent.
-  struct A { int &&r = 0; }; // expected-warning {{binding reference member 'r' to a temporary}} expected-note {{here}}
+  // temporaries.
+  struct A { int &&r = 0; }; // expected-warning 2{{not supported}}
   struct B { A x, y; };
-  B b = {};
+  B b = {}; // expected-note 2{{used here}}
 }
 
 namespace pr33140_3 {

Modified: cfe/trunk/test/SemaCXX/member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/member-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-init.cpp Tue Jul 17 15:24:09 2018
@@ -86,9 +86,8 @@ namespace PR14838 {
   };
   struct thing {};
   struct another {
-    another() : r(thing()) {}
+    another() : r(thing()) {} // expected-error {{binds to a temporary object}}
     // expected-error at -1 {{temporary of type 'PR14838::function' has private destructor}}
-    // expected-warning at -2 {{binding reference member 'r' to a temporary value}}
     const function &r; // expected-note {{reference member declared here}}
   } af;
 }

Modified: cfe/trunk/test/SemaCXX/warn-dangling-field.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-dangling-field.cpp?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-dangling-field.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-dangling-field.cpp Tue Jul 17 15:24:09 2018
@@ -20,7 +20,7 @@ struct S {
 
 struct S2 {
   const X &x; // expected-note {{reference member declared here}}
-  S2(int i) : x(i) {} // expected-warning {{binding reference member 'x' to a temporary}}
+  S2(int i) : x(i) {} // expected-error {{member 'x' binds to a temporary}}
 };
 
 struct S3 {
@@ -43,9 +43,9 @@ 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}}
+  S6() : s5 { 0 } {} // expected-error {{reference subobject of member 's5' binds to a temporary}}
 };
 
 struct S7 : S5 {
-  S7() : S5 { 0 } {} // expected-warning {{binding reference member 'x' to a temporary}}
+  S7() : S5 { 0 } {} // expected-error {{reference member 'x' binds to a temporary}}
 };

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=337329&r1=337328&r2=337329&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Tue Jul 17 15:24:09 2018
@@ -9991,7 +9991,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1696">1696</a></td>
     <td>CD4</td>
     <td>Temporary lifetime and non-static data member initializers</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr class="open" id="1697">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1697">1697</a></td>
@@ -10705,7 +10705,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1815">1815</a></td>
     <td>CD4</td>
     <td>Lifetime extension in aggregate initialization</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="none" align="center">No</td>
   </tr>
   <tr id="1816">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1816">1816</a></td>




More information about the cfe-commits mailing list