summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Hahn <florian.hahn@arm.com>2018-07-17 09:23:31 +0000
committerFlorian Hahn <florian.hahn@arm.com>2018-07-17 09:23:31 +0000
commit28deda3b5839098b427e528ad93bcfa434806a74 (patch)
tree806935f84eda19055950c0859e3939e21d44cb02
parentde3003c4189d27f04678d5295dd6b4d4700f7d3f (diff)
Temporarily revert r337226 "Restructure checking for, and warning on, lifetime extension."
This change breaks on ARM because pointers to clang::InitializedEntity are only 4 byte aligned and do not have 3 bits to store values. A possible solution would be to change the fields in clang::InitializedEntity to enforce a bigger alignment requirement. The error message is llvm/include/llvm/ADT/PointerIntPair.h:132:3: error: static_assert failed "PointerIntPair with integer size too large for pointer" static_assert(IntBits <= PtrTraits::NumLowBitsAvailable, include/llvm/ADT/PointerIntPair.h:73:13: note: in instantiation of template class 'llvm::PointerIntPairInfo<const clang::InitializedEntity *, 3, llvm::PointerLikeTypeTraits<const clang::InitializedEntity *> >' requested here Value = Info::updateInt(Info::updatePointer(0, PtrVal), llvm/include/llvm/ADT/PointerIntPair.h:51:5: note: in instantiation of member function 'llvm::PointerIntPair<const clang::InitializedEntity *, 3, (anonymous namespace)::LifetimeKind, llvm::PointerLikeTypeTraits<const clang::InitializedEntity *>, llvm::PointerIntPairInfo<const clang::InitializedEntity *, 3, llvm::PointerLikeTypeTraits<const clang::InitializedEntity *> > >::setPointerAndInt' requested here setPointerAndInt(PtrVal, IntVal); ^ llvm/tools/clang/lib/Sema/SemaInit.cpp:6237:12: note: in instantiation of member function 'llvm::PointerIntPair<const clang::InitializedEntity *, 3, (anonymous namespace)::LifetimeKind, llvm::PointerLikeTypeTraits<const clang::InitializedEntity *>, llvm::PointerIntPairInfo<const clang::InitializedEntity *, 3, llvm::PointerLikeTypeTraits<const clang::InitializedEntity *> > >::PointerIntPair' requested here return {Entity, LK_Extended}; Full log here: http://lab.llvm.org:8011/builders/clang-cmake-armv7-global-isel/builds/1330 http://lab.llvm.org:8011/builders/clang-cmake-armv7-full/builds/1394 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@337255 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td40
-rw-r--r--include/clang/Sema/Initialization.h34
-rw-r--r--include/clang/Sema/Sema.h5
-rw-r--r--lib/Sema/SemaDeclCXX.cpp7
-rw-r--r--lib/Sema/SemaExprCXX.cpp7
-rw-r--r--lib/Sema/SemaInit.cpp370
-rw-r--r--test/Analysis/initializer.cpp23
-rw-r--r--test/CXX/drs/dr16xx.cpp94
-rw-r--r--test/CXX/drs/dr18xx.cpp11
-rw-r--r--test/CXX/special/class.copy/p11.0x.copy.cpp13
-rw-r--r--test/CXX/special/class.copy/p11.0x.move.cpp2
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp6
-rw-r--r--test/CXX/temp/temp.param/p5.cpp12
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp30
-rw-r--r--test/CodeGenCXX/temporaries.cpp27
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp9
-rw-r--r--test/SemaCXX/constexpr-default-arg.cpp4
-rw-r--r--test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp9
-rw-r--r--test/SemaCXX/eval-crashes.cpp6
-rw-r--r--test/SemaCXX/member-init.cpp3
-rw-r--r--test/SemaCXX/warn-dangling-field.cpp6
-rw-r--r--www/cxx_dr_status.html4
23 files changed, 240 insertions, 483 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index e27dc0d764..e021cf6975 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -272,7 +272,6 @@ def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">;
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">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index acfdd260cd..c32b5ea07a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2049,6 +2049,10 @@ def err_implied_std_initializer_list_not_found : Error<
"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<
@@ -7840,39 +7844,13 @@ def warn_bind_ref_member_to_parameter : Warning<
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 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">;
+def note_ref_subobject_of_member_declared_here : Note<
+ "member with reference subobject declared here">;
// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 774a2c9ff9..1e6423c99d 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -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,10 +158,6 @@ 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 {
@@ -207,7 +203,7 @@ private:
/// Create the initialization entity for a variable.
InitializedEntity(VarDecl *Var, EntityKind EK = EK_Variable)
- : Kind(EK), Type(Var->getType()), Variable{Var, false, false} {}
+ : Kind(EK), Type(Var->getType()), Variable{Var, false} {}
/// Create the initialization entity for the result of a
/// function, throwing an object, performing an explicit cast, or
@@ -221,9 +217,9 @@ private:
/// Create the initialization entity for a member subobject.
InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent,
- bool Implicit, bool DefaultMemberInit)
+ bool Implicit)
: Kind(EK_Member), Parent(Parent), Type(Member->getType()),
- Variable{Member, Implicit, DefaultMemberInit} {}
+ Variable{Member, Implicit} {}
/// Create the initialization entity for an array element.
InitializedEntity(ASTContext &Context, unsigned Index,
@@ -343,27 +339,21 @@ 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, false);
+ return InitializedEntity(Member, Parent, Implicit);
}
-
+
/// 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, false);
- }
-
- /// Create the initialization entity for a default member initializer.
- static InitializedEntity
- InitializeMemberFromDefaultMemberInitializer(FieldDecl *Member) {
- return InitializedEntity(Member, nullptr, false, true);
+ return InitializedEntity(Member->getAnonField(), Parent, Implicit);
}
/// Create the initialization entity for an array element.
@@ -463,12 +453,6 @@ 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 {
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index f13e423cef..2425dff005 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2582,11 +2582,6 @@ 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);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index eda6e16195..63d01c9d85 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3621,8 +3621,7 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
ExprResult Init = InitExpr;
if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
- InitializedEntity Entity =
- InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD);
+ InitializedEntity Entity = InitializedEntity::InitializeMember(FD);
InitializationKind Kind =
FD->getInClassInitStyle() == ICIS_ListInit
? InitializationKind::CreateDirectList(InitExpr->getLocStart(),
@@ -4647,10 +4646,6 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
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)
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index a7ad8e322d..fbf572e398 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1864,6 +1864,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
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 &&
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index f94eabd671..320d93a99a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -572,7 +572,6 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
hadError = true;
return;
}
- SemaRef.checkInitializerLifetime(MemberEntity, DIE.get());
if (Init < NumInits)
ILE->setInit(Init, DIE.get());
else {
@@ -6198,43 +6197,17 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
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 LifetimeResult getEntityForTemporaryLifetimeExtension(
+static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
const InitializedEntity *Entity,
- const InitializedEntity *InitField = nullptr) {
+ const InitializedEntity *FallbackDecl = nullptr) {
// C++11 [class.temporary]p5:
switch (Entity->getKind()) {
case InitializedEntity::EK_Variable:
// The temporary [...] persists for the lifetime of the reference
- return {Entity, LK_Extended};
+ return Entity;
case InitializedEntity::EK_Member:
// For subobjects, we look at the complete object.
@@ -6243,43 +6216,29 @@ static LifetimeResult getEntityForTemporaryLifetimeExtension(
Entity);
// except:
- // 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};
+ // -- A temporary bound to a reference member in a constructor's
+ // ctor-initializer persists until the constructor exits.
+ return Entity;
case InitializedEntity::EK_Binding:
// Per [dcl.decomp]p3, the binding is treated as a variable of reference
// type.
- return {Entity, LK_Extended};
+ return Entity;
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, LK_New};
+ return nullptr;
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_CompoundLiteralInit:
@@ -6287,26 +6246,25 @@ static LifetimeResult getEntityForTemporaryLifetimeExtension(
// 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, LK_FullExpression};
+ return nullptr;
case InitializedEntity::EK_ArrayElement:
// For subobjects, we look at the complete object.
return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
- InitField);
+ FallbackDecl);
case InitializedEntity::EK_Base:
// For subobjects, we look at the complete object.
if (Entity->getParent())
return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
- InitField);
- return {InitField, LK_MemInitializer};
-
+ Entity);
+ LLVM_FALLTHROUGH;
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 outermost field decl as the context.
- return {InitField, LK_MemInitializer};
+ // In this case, use the innermost field decl as the context.
+ return FallbackDecl;
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
@@ -6314,54 +6272,30 @@ static LifetimeResult getEntityForTemporaryLifetimeExtension(
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
- return {nullptr, LK_FullExpression};
+ return nullptr;
}
llvm_unreachable("unknown entity kind");
}
-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);
+static void performLifetimeExtension(Expr *Init,
+ const InitializedEntity *ExtendingEntity);
+/// 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 this is just redundant braces around an initializer, step over it.
- if (ILE->isTransparent())
+ if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
+ // This is just redundant braces around an initializer. Step over it.
Init = ILE->getInit(0);
+ }
}
// Step over any subobject adjustments; we may have a materialized
@@ -6378,65 +6312,40 @@ visitTemporariesExtendedByReferenceBinding(IndirectTemporaryPath &Path,
// 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 (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
- if (Visit(Path, MTE, EK))
- visitTemporariesExtendedByInitializer(Path, MTE->GetTemporaryExpr(),
- Visit);
+ 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;
}
-}
-
-/// 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();
- }
+ 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) {
// 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();
- // 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 (CXXStdInitializerListExpr *ILE =
+ dyn_cast<CXXStdInitializerListExpr>(Init)) {
+ performReferenceExtension(ILE->getSubExpr(), ExtendingEntity);
+ return;
+ }
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)
- visitTemporariesExtendedByInitializer(Path, ILE->getInit(I), Visit);
+ performLifetimeExtension(ILE->getInit(I), ExtendingEntity);
return;
}
@@ -6448,8 +6357,7 @@ static void visitTemporariesExtendedByInitializer(IndirectTemporaryPath &Path,
// bound to temporaries, those temporaries are also lifetime-extended.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
- visitTemporariesExtendedByReferenceBinding(Path, ILE->getInit(0),
- EK_ReferenceBinding, Visit);
+ performReferenceExtension(ILE->getInit(0), ExtendingEntity);
else {
unsigned Index = 0;
for (const auto *I : RD->fields()) {
@@ -6459,13 +6367,13 @@ static void visitTemporariesExtendedByInitializer(IndirectTemporaryPath &Path,
continue;
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
- 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,
+ 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,
// we should recursively lifetime-extend that initializer.
- visitTemporariesExtendedByInitializer(Path, SubInit, Visit);
+ performLifetimeExtension(SubInit, ExtendingEntity);
++Index;
}
}
@@ -6473,123 +6381,37 @@ static void visitTemporariesExtendedByInitializer(IndirectTemporaryPath &Path,
}
}
-/// 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;
+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;
}
- // 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();
+ bool IsSubobjectMember = false;
+ for (const InitializedEntity *Ent = Entity.getParent(); Ent;
+ Ent = Ent->getParent()) {
+ if (Ent->getKind() != InitializedEntity::EK_Base) {
+ IsSubobjectMember = true;
+ break;
}
}
-
- // 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);
+ 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;
+ }
}
static void DiagnoseNarrowingInInitList(Sema &S,
@@ -7016,9 +6838,14 @@ 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.
- S.checkInitializerLifetime(Entity, CurInit.get());
+ // 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());
CheckForNullPointerDereference(S, CurInit.get());
break;
@@ -7034,17 +6861,23 @@ 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.
- S.checkInitializerLifetime(Entity, CurInit.get());
+ if (const InitializedEntity *ExtendingEntity =
+ getEntityForTemporaryLifetimeExtension(&Entity))
+ if (performReferenceExtension(MTE, ExtendingEntity))
+ warnOnLifetimeExtension(S, Entity, CurInit.get(),
+ /*IsInitializerList=*/false,
+ ExtendingEntity->getDecl());
// 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;
}
@@ -7487,12 +7320,17 @@ InitializationSequence::Perform(Sema &S,
CurInit.get()->getType(), CurInit.get(),
/*BoundToLvalueReference=*/false);
- // 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());
+ 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);
// Bind the result, in case the library has given initializer_list a
// non-trivial destructor.
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index 0cb68c4a97..b73a94f1db 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -178,6 +178,29 @@ 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@-1 {{binding reference member 'ms' to a temporary value}}
+ // expected-warning@-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 {
diff --git a/test/CXX/drs/dr16xx.cpp b/test/CXX/drs/dr16xx.cpp
index 54648cfe96..e0af95ac39 100644
--- a/test/CXX/drs/dr16xx.cpp
+++ b/test/CXX/drs/dr16xx.cpp
@@ -9,20 +9,6 @@
#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; };
@@ -283,83 +269,3 @@ 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@-2 {{binds to a temporary}}
- // expected-note@-4 {{here}}
-#else
- // expected-warning-re@-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
-}
diff --git a/test/CXX/drs/dr18xx.cpp b/test/CXX/drs/dr18xx.cpp
index f6a4676bc7..a0f470ed4a 100644
--- a/test/CXX/drs/dr18xx.cpp
+++ b/test/CXX/drs/dr18xx.cpp
@@ -30,17 +30,6 @@ 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; };
diff --git a/test/CXX/special/class.copy/p11.0x.copy.cpp b/test/CXX/special/class.copy/p11.0x.copy.cpp
index a4d0cdcdc7..1ca0143d09 100644
--- a/test/CXX/special/class.copy/p11.0x.copy.cpp
+++ b/test/CXX/special/class.copy/p11.0x.copy.cpp
@@ -121,22 +121,13 @@ 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 = static_cast<int&&>(some_int); // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
+ int && ri = 1; // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}}
+ // expected-warning@-1{{binding reference member 'ri' to a temporary}} expected-note@-1 {{here}}
};
RValue RVa;
RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}}
-// 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@-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&);
diff --git a/test/CXX/special/class.copy/p11.0x.move.cpp b/test/CXX/special/class.copy/p11.0x.move.cpp
index 5b016836e9..ab4259548e 100644
--- a/test/CXX/special/class.copy/p11.0x.move.cpp
+++ b/test/CXX/special/class.copy/p11.0x.move.cpp
@@ -145,7 +145,7 @@ HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy c
// The restriction on rvalue reference members applies to only the copy
// constructor.
struct RValue {
- int &&ri = 1;
+ int &&ri = 1; // expected-warning {{binding reference member 'ri' to a temporary}} expected-note {{here}}
RValue(RValue&&);
};
RValue::RValue(RValue&&) = default;
diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp
index 5558313ce7..2360345a48 100644
--- a/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/test/CXX/special/class.ctor/p5-0x.cpp
@@ -43,12 +43,8 @@ class NotDeleted2a { int &a = n; };
NotDeleted2a nd2a;
class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
NotDeleted2b nd2b;
-class NotDeleted2c { int &&a = static_cast<int&&>(n); };
+class NotDeleted2c { int &&a = 0; }; // expected-warning {{binding reference member 'a' to a temporary}} expected-note {{here}}
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
diff --git a/test/CXX/temp/temp.param/p5.cpp b/test/CXX/temp/temp.param/p5.cpp
index de902a5e4d..aa0d7e92b9 100644
--- a/test/CXX/temp/temp.param/p5.cpp
+++ b/test/CXX/temp/temp.param/p5.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -verify %s -std=c++14
-template<const int I> struct S { // expected-note {{in default member initializer}}
+template<const int I> struct S {
decltype(I) n;
- int &&r = I; // expected-error {{reference member 'r' binds to a temporary object}}
+ int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
};
-S<5> s; // expected-note {{implicit default constructor}}
+S<5> s; // expected-note {{instantiation}}
-template<typename T, T v> struct U { // expected-note {{in default member initializer}}
+template<typename T, T v> struct U {
decltype(v) n;
- int &&r = v; // expected-error {{reference member 'r' binds to a temporary object}}
+ int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
};
-U<const int, 6> u; // expected-note {{implicit default constructor}}
+U<const int, 6> u; // expected-note {{instantiation}}
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
index 0184a1d6e7..3299763997 100644
--- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -236,6 +236,36 @@ 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]
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index 21372effbc..bad51ba353 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -198,6 +198,20 @@ 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() {
@@ -802,3 +816,16 @@ 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(
+}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index e921634b1b..4b4bd43634 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1892,15 +1892,14 @@ namespace Lifetime {
}
constexpr int &get(int &&n) { return n; }
- constexpr int &&get_rv(int &&n) { return static_cast<int&&>(n); }
struct S {
- int &&r;
+ int &&r; // expected-note 2{{declared here}}
int &s;
int t;
- 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 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 int k1 = S().t; // expected-error {{constant expression}} expected-note {{in call}}
+ constexpr int k1 = S().t; // ok, int is lifetime-extended to end of constructor
constexpr int k2 = S(0).t; // expected-error {{constant expression}} expected-note {{in call}}
}
diff --git a/test/SemaCXX/constexpr-default-arg.cpp b/test/SemaCXX/constexpr-default-arg.cpp
index 165c31aab6..2fc873c3e5 100644
--- a/test/SemaCXX/constexpr-default-arg.cpp
+++ b/test/SemaCXX/constexpr-default-arg.cpp
@@ -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 2{{not supported}}
+struct A { int &&r = 0; }; // expected-warning {{binding reference member}} // expected-note {{reference member declared here}}
struct B { A x, y; };
-B b = {}; // expected-note 2{{in default member initializer for field 'r' used here}}
+B b = {};
}
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index ece014d93a..860a4aa6c6 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -153,14 +153,13 @@ void dangle() {
}
struct haslist1 {
- 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}}
+ 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}}
haslist1();
};
-haslist1::haslist1() // expected-note {{used here}}
-: il{1, 2, 3} // expected-error {{backing array for 'std::initializer_list' member 'il' is a temporary object}}
+haslist1::haslist1()
+: il{1, 2, 3} // expected-warning{{at the end of the constructor}}
{}
namespace PR12119 {
diff --git a/test/SemaCXX/eval-crashes.cpp b/test/SemaCXX/eval-crashes.cpp
index 33bde75de6..23946845d8 100644
--- a/test/SemaCXX/eval-crashes.cpp
+++ b/test/SemaCXX/eval-crashes.cpp
@@ -26,10 +26,10 @@ namespace pr33140_0b {
namespace pr33140_2 {
// FIXME: The declaration of 'b' below should lifetime-extend two int
- // temporaries.
- struct A { int &&r = 0; }; // expected-warning 2{{not supported}}
+ // temporaries, invalidating this warning to some extent.
+ struct A { int &&r = 0; }; // expected-warning {{binding reference member 'r' to a temporary}} expected-note {{here}}
struct B { A x, y; };
- B b = {}; // expected-note 2{{used here}}
+ B b = {};
}
namespace pr33140_3 {
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index 8a13eca2f1..ad4a8f15b2 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -86,8 +86,9 @@ namespace PR14838 {
};
struct thing {};
struct another {
- another() : r(thing()) {} // expected-error {{binds to a temporary object}}
+ another() : r(thing()) {}
// expected-error@-1 {{temporary of type 'PR14838::function' has private destructor}}
+ // expected-warning@-2 {{binding reference member 'r' to a temporary value}}
const function &r; // expected-note {{reference member declared here}}
} af;
}
diff --git a/test/SemaCXX/warn-dangling-field.cpp b/test/SemaCXX/warn-dangling-field.cpp
index 97d4331c1f..eb65bd0669 100644
--- a/test/SemaCXX/warn-dangling-field.cpp
+++ b/test/SemaCXX/warn-dangling-field.cpp
@@ -20,7 +20,7 @@ struct S {
struct S2 {
const X &x; // expected-note {{reference member declared here}}
- S2(int i) : x(i) {} // expected-error {{member 'x' binds to a temporary}}
+ S2(int i) : x(i) {} // expected-warning {{binding reference member 'x' 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-error {{reference subobject of member 's5' binds to a temporary}}
+ S6() : s5 { 0 } {} // expected-warning {{binding reference subobject of member 's5' to a temporary}}
};
struct S7 : S5 {
- S7() : S5 { 0 } {} // expected-error {{reference member 'x' binds to a temporary}}
+ S7() : S5 { 0 } {} // expected-warning {{binding reference member 'x' to a temporary}}
};
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index 04dd0eae1c..93d4ee93fb 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -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="svn" align="center">SVN</td>
+ <td class="none" align="center">Unknown</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">No</td>
+ <td class="none" align="center">Unknown</td>
</tr>
<tr id="1816">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1816">1816</a></td>