Hi Richard, this commit seems to cause invalid warning in the following example:
struct foo { foo(char *x) : x_(&x[10]) {} // private: char *x_; }; The warning itself: 1.cpp:2:21: warning: initializing pointer member 'x_' with the stack address of parameter 'x' [-Wdangling-field] I'll revert the change to unbreak our integrate. On Sat, Jul 21, 2018 at 12:31 AM Richard Smith via cfe-commits < cfe-commits@lists.llvm.org> wrote: > Author: rsmith > Date: Fri Jul 20 15:25:55 2018 > New Revision: 337627 > > URL: http://llvm.org/viewvc/llvm-project?rev=337627&view=rev > Log: > Fold dangling-field warning into general initialization lifetime checks. > > Modified: > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/lib/Sema/SemaDeclCXX.cpp > cfe/trunk/lib/Sema/SemaInit.cpp > cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp > cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=337627&r1=337626&r2=337627&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jul 20 > 15:25:55 2018 > @@ -7870,11 +7870,11 @@ def note_ref_var_local_bind : Note< > // Check for initializing a member variable with the address or a > reference to > // a constructor parameter. > def warn_bind_ref_member_to_parameter : Warning< > - "binding reference member %0 to stack allocated parameter %1">, > - InGroup<DanglingField>; > + "binding reference member %0 to stack allocated " > + "%select{variable|parameter}2 %1">, InGroup<DanglingField>; > def warn_init_ptr_member_to_parameter_addr : Warning< > - "initializing pointer member %0 with the stack address of parameter > %1">, > - InGroup<DanglingField>; > + "initializing pointer member %0 with the stack address of " > + "%select{variable|parameter}2 %1">, InGroup<DanglingField>; > def note_ref_or_ptr_member_declared_here : Note< > "%select{reference|pointer}0 member declared here">; > > > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=337627&r1=337626&r2=337627&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Jul 20 15:25:55 2018 > @@ -3946,53 +3946,6 @@ Sema::BuildMemInitializer(Decl *Construc > return BuildBaseInitializer(BaseType, TInfo, Init, ClassDecl, > EllipsisLoc); > } > > -/// Checks a member initializer expression for cases where reference (or > -/// pointer) members are bound to by-value parameters (or their > addresses). > -static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, > - Expr *Init, > - SourceLocation IdLoc) { > - QualType MemberTy = Member->getType(); > - > - // We only handle pointers and references currently. > - // FIXME: Would this be relevant for ObjC object pointers? Or block > pointers? > - if (!MemberTy->isReferenceType() && !MemberTy->isPointerType()) > - return; > - > - const bool IsPointer = MemberTy->isPointerType(); > - if (IsPointer) { > - if (const UnaryOperator *Op > - = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) { > - // The only case we're worried about with pointers requires taking > the > - // address. > - if (Op->getOpcode() != UO_AddrOf) > - return; > - > - Init = Op->getSubExpr(); > - } else { > - // We only handle address-of expression initializers for pointers. > - return; > - } > - } > - > - if (const DeclRefExpr *DRE = > dyn_cast<DeclRefExpr>(Init->IgnoreParens())) { > - // We only warn when referring to a non-reference parameter > declaration. > - const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl()); > - if (!Parameter || Parameter->getType()->isReferenceType()) > - return; > - > - S.Diag(Init->getExprLoc(), > - IsPointer ? diag::warn_init_ptr_member_to_parameter_addr > - : diag::warn_bind_ref_member_to_parameter) > - << Member << Parameter << Init->getSourceRange(); > - } else { > - // Other initializers are fine. > - return; > - } > - > - S.Diag(Member->getLocation(), > diag::note_ref_or_ptr_member_declared_here) > - << (unsigned)IsPointer; > -} > - > MemInitResult > Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, > SourceLocation IdLoc) { > @@ -4047,8 +4000,6 @@ Sema::BuildMemberInitializer(ValueDecl * > if (MemberInit.isInvalid()) > return true; > > - CheckForDanglingReferenceOrPointer(*this, Member, MemberInit.get(), > IdLoc); > - > // C++11 [class.base.init]p7: > // The initialization of each base and member constitutes a > // full-expression. > > Modified: cfe/trunk/lib/Sema/SemaInit.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=337627&r1=337626&r2=337627&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaInit.cpp (original) > +++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Jul 20 15:25:55 2018 > @@ -6227,7 +6227,7 @@ using LifetimeResult = > /// 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 LifetimeResult getEntityLifetime( > const InitializedEntity *Entity, > const InitializedEntity *InitField = nullptr) { > // C++11 [class.temporary]p5: > @@ -6239,8 +6239,7 @@ static LifetimeResult getEntityForTempor > case InitializedEntity::EK_Member: > // For subobjects, we look at the complete object. > if (Entity->getParent()) > - return getEntityForTemporaryLifetimeExtension(Entity->getParent(), > - Entity); > + return getEntityLifetime(Entity->getParent(), Entity); > > // except: > // C++17 [class.base.init]p8: > @@ -6291,14 +6290,12 @@ static LifetimeResult getEntityForTempor > > case InitializedEntity::EK_ArrayElement: > // For subobjects, we look at the complete object. > - return getEntityForTemporaryLifetimeExtension(Entity->getParent(), > - InitField); > + return getEntityLifetime(Entity->getParent(), InitField); > > case InitializedEntity::EK_Base: > // For subobjects, we look at the complete object. > if (Entity->getParent()) > - return getEntityForTemporaryLifetimeExtension(Entity->getParent(), > - InitField); > + return getEntityLifetime(Entity->getParent(), InitField); > return {InitField, LK_MemInitializer}; > > case InitializedEntity::EK_Delegating: > @@ -6311,46 +6308,61 @@ static LifetimeResult getEntityForTempor > case InitializedEntity::EK_BlockElement: > case InitializedEntity::EK_LambdaToBlockConversionBlockElement: > case InitializedEntity::EK_LambdaCapture: > - case InitializedEntity::EK_Exception: > case InitializedEntity::EK_VectorElement: > case InitializedEntity::EK_ComplexElement: > return {nullptr, LK_FullExpression}; > + > + case InitializedEntity::EK_Exception: > + // FIXME: Can we diagnose lifetime problems with exceptions? > + return {nullptr, LK_FullExpression}; > } > llvm_unreachable("unknown entity kind"); > } > > namespace { > -enum ExtensionKind { > +enum ReferenceKind { > /// Lifetime would be extended by a reference binding to a temporary. > - EK_ReferenceBinding, > + RK_ReferenceBinding, > /// Lifetime would be extended by a std::initializer_list object > binding to > /// its backing array. > - EK_StdInitializerList, > + RK_StdInitializerList, > }; > -using IndirectTemporaryPathEntry = > - llvm::PointerUnion<CXXDefaultInitExpr *, ValueDecl *>; > -using IndirectTemporaryPath = > llvm::SmallVectorImpl<IndirectTemporaryPathEntry>; > + > +/// A temporary or local variable. > +using Local = llvm::PointerUnion<MaterializeTemporaryExpr*, ValueDecl*>; > + > +/// Expressions we stepped over when looking for the local state. Any > steps > +/// that would inhibit lifetime extension or take us out of > subexpressions of > +/// the initializer are included. > +struct IndirectLocalPathEntry { > + enum { > + DefaultInit, > + AddressOf, > + } Kind; > + Expr *E; > +}; > + > +using IndirectLocalPath = llvm::SmallVectorImpl<IndirectLocalPathEntry>; > > struct RevertToOldSizeRAII { > - IndirectTemporaryPath &Path; > + IndirectLocalPath &Path; > unsigned OldSize = Path.size(); > - RevertToOldSizeRAII(IndirectTemporaryPath &Path) : Path(Path) {} > + RevertToOldSizeRAII(IndirectLocalPath &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) { > +template <typename LocalVisitor> > +static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, > + Expr *Init, LocalVisitor > Visit, > + bool RevisitSubinits); > + > +/// Visit the locals that would be reachable through a reference bound to > the > +/// glvalue expression \c Init. > +template <typename LocalVisitor> > +static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, > + Expr *Init, > ReferenceKind RK, > + LocalVisitor Visit) { > RevertToOldSizeRAII RAII(Path); > > // Walk past any constructs which we can lifetime-extend across. > @@ -6382,7 +6394,7 @@ visitTemporariesExtendedByReferenceBindi > // 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); > + Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE}); > Init = DIE->getExpr(); > > if (auto *EWC = dyn_cast<ExprWithCleanups>(Init)) > @@ -6391,25 +6403,36 @@ visitTemporariesExtendedByReferenceBindi > } while (Init != Old); > > if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) { > - if (Visit(Path, MTE, EK)) > - visitTemporariesExtendedByInitializer(Path, MTE->GetTemporaryExpr(), > - Visit); > + if (Visit(Path, Local(MTE), RK)) > + visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), > Visit, > + true); > + } > + > + // If we find the name of a local non-reference parameter, we could > have a > + // lifetime problem. > + if (auto *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) { > + auto *VD = dyn_cast<VarDecl>(DRE->getDecl()); > + if (VD && VD->hasLocalStorage() && > + !DRE->refersToEnclosingVariableOrCapture()) { > + // FIXME: Recurse to the initializer of a local reference. > + if (!VD->getType()->isReferenceType()) > + Visit(Path, Local(VD), RK); > + } > } > } > > -/// 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) > { > +/// Visit the locals that would be reachable through an object > initialized by > +/// the prvalue expression \c Init. > +template <typename LocalVisitor> > +static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, > + Expr *Init, LocalVisitor > Visit, > + bool RevisitSubinits) { > 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); > + Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE}); > Init = DIE->getExpr(); > > if (auto *EWC = dyn_cast<ExprWithCleanups>(Init)) > @@ -6426,17 +6449,24 @@ static void visitTemporariesExtendedByIn > // 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); > + return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(), > + RK_StdInitializerList, > Visit); > > if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { > + // We already visited the elements of this initializer list while > + // performing the initialization. Don't visit them again unless we've > + // changed the lifetime of the initialized entity. > + if (!RevisitSubinits) > + return; > + > if (ILE->isTransparent()) > - return visitTemporariesExtendedByInitializer(Path, ILE->getInit(0), > - Visit); > + return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), > Visit, > + RevisitSubinits); > > if (ILE->getType()->isArrayType()) { > for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) > - visitTemporariesExtendedByInitializer(Path, ILE->getInit(I), > Visit); > + visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit, > + RevisitSubinits); > return; > } > > @@ -6448,8 +6478,8 @@ static void visitTemporariesExtendedByIn > // 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); > + visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0), > + RK_ReferenceBinding, Visit); > else { > unsigned Index = 0; > for (const auto *I : RD->fields()) { > @@ -6459,25 +6489,38 @@ static void visitTemporariesExtendedByIn > continue; > Expr *SubInit = ILE->getInit(Index); > if (I->getType()->isReferenceType()) > - visitTemporariesExtendedByReferenceBinding( > - Path, SubInit, EK_ReferenceBinding, Visit); > + visitLocalsRetainedByReferenceBinding(Path, SubInit, > + RK_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. > - visitTemporariesExtendedByInitializer(Path, SubInit, Visit); > + visitLocalsRetainedByInitializer(Path, SubInit, Visit, > + RevisitSubinits); > ++Index; > } > } > } > + return; > + } > + > + // If the initializer is the address of a local, we could have a > lifetime > + // problem. > + if (auto *Op = dyn_cast<UnaryOperator>(Init->IgnoreParenImpCasts())) { > + if (Op->getOpcode() == UO_AddrOf) { > + Path.push_back({IndirectLocalPathEntry::AddressOf, Op}); > + Init = Op->getSubExpr(); > + return visitLocalsRetainedByReferenceBinding(Path, Init, > + RK_ReferenceBinding, > Visit); > + } > } > } > > /// 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) { > +static bool shouldLifetimeExtendThroughPath(const IndirectLocalPath > &Path) { > for (auto Elem : Path) { > - if (!Elem.is<CXXDefaultInitExpr*>()) > + if (Elem.Kind != IndirectLocalPathEntry::DefaultInit) > return false; > } > return true; > @@ -6485,7 +6528,7 @@ static bool shouldLifetimeExtendThroughP > > void Sema::checkInitializerLifetime(const InitializedEntity &Entity, > Expr *Init) { > - LifetimeResult LR = getEntityForTemporaryLifetimeExtension(&Entity); > + LifetimeResult LR = getEntityLifetime(&Entity); > LifetimeKind LK = LR.getInt(); > const InitializedEntity *ExtendingEntity = LR.getPointer(); > > @@ -6494,9 +6537,54 @@ void Sema::checkInitializerLifetime(cons > if (LK == LK_FullExpression) > return; > > - auto TemporaryVisitor = [&](IndirectTemporaryPath &Path, > - MaterializeTemporaryExpr *MTE, > - ExtensionKind EK) -> bool { > + auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L, > + ReferenceKind RK) -> bool { > + // If we found a path to a local variable or similar, check whether > the > + // initialized object will outlive it. > + if (auto *VD = L.dyn_cast<ValueDecl*>()) { > + switch (LK) { > + case LK_FullExpression: > + llvm_unreachable("already handled this"); > + > + case LK_Extended: > + break; > + > + case LK_MemInitializer: { > + // Paths via a default initializer can only occur during error > recovery > + // (there's no other way that a default initializer can refer to a > + // local). Don't produce a bogus warning on those cases. > + if (std::any_of(Path.begin(), Path.end(), > [](IndirectLocalPathEntry E) { > + return E.Kind == IndirectLocalPathEntry::DefaultInit; > + })) > + break; > + > + if (auto *Member = > + ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { > + bool AddressTaken = > + !Path.empty() && > + Path.back().Kind == IndirectLocalPathEntry::AddressOf; > + Diag(Init->getExprLoc(), > + AddressTaken ? diag::warn_init_ptr_member_to_parameter_addr > + : diag::warn_bind_ref_member_to_parameter) > + << Member << VD << isa<ParmVarDecl>(VD) << > Init->getSourceRange(); > + Diag(Member->getLocation(), > + diag::note_ref_or_ptr_member_declared_here) > + << (unsigned)AddressTaken; > + } > + break; > + } > + > + case LK_New: > + break; > + > + case LK_Return: > + // FIXME: Move -Wreturn-stack-address checks here. > + return false; > + } > + return false; > + } > + > + auto *MTE = L.get<MaterializeTemporaryExpr*>(); > switch (LK) { > case LK_FullExpression: > llvm_unreachable("already handled this"); > @@ -6520,11 +6608,11 @@ void Sema::checkInitializerLifetime(cons > // would be to clone the initializer expression on each use that > would > // lifetime extend its temporaries. > Diag(MTE->getExprLoc(), > - EK == EK_ReferenceBinding > + RK == RK_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"); > + // FIXME: Warn on this. > } > break; > > @@ -6532,18 +6620,20 @@ void Sema::checkInitializerLifetime(cons > // 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()) { > + if (auto *ExtendingDecl = > + ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { > bool IsSubobjectMember = ExtendingEntity != &Entity; > Diag(MTE->getExprLoc(), diag::err_bind_ref_member_to_temporary) > << ExtendingDecl << Init->getSourceRange() << > IsSubobjectMember > - << EK; > + << RK; > // 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*>()) { > + if (Path.empty() || > + Path.back().Kind != IndirectLocalPathEntry::DefaultInit) { > Diag(ExtendingDecl->getLocation(), > diag::note_lifetime_extending_member_declared_here) > - << EK << IsSubobjectMember; > + << RK << IsSubobjectMember; > } > } else { > // We have a mem-initializer but no particular field within it; > this > @@ -6557,7 +6647,7 @@ void Sema::checkInitializerLifetime(cons > break; > > case LK_New: > - if (EK == EK_ReferenceBinding) { > + if (RK == RK_ReferenceBinding) { > Diag(MTE->getExprLoc(), diag::warn_new_dangling_reference); > } else { > Diag(MTE->getExprLoc(), diag::warn_new_dangling_initializer_list) > @@ -6573,9 +6663,14 @@ void Sema::checkInitializerLifetime(cons > // 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(); > + switch (Elem.Kind) { > + case IndirectLocalPathEntry::DefaultInit: > + Diag(Elem.E->getExprLoc(), > diag::note_in_default_member_initalizer_here) > + << cast<CXXDefaultInitExpr>(Elem.E)->getField(); > + break; > + > + case IndirectLocalPathEntry::AddressOf: > + break; > } > } > > @@ -6584,12 +6679,12 @@ void Sema::checkInitializerLifetime(cons > return false; > }; > > - llvm::SmallVector<IndirectTemporaryPathEntry, 8> Path; > + llvm::SmallVector<IndirectLocalPathEntry, 8> Path; > if (Init->isGLValue()) > - visitTemporariesExtendedByReferenceBinding(Path, Init, > EK_ReferenceBinding, > - TemporaryVisitor); > + visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding, > + TemporaryVisitor); > else > - visitTemporariesExtendedByInitializer(Path, Init, TemporaryVisitor); > + visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false); > } > > static void DiagnoseNarrowingInInitList(Sema &S, > @@ -6853,6 +6948,7 @@ InitializationSequence::Perform(Sema &S, > > // Diagnose cases where we initialize a pointer to an array temporary, > and the > // pointer obviously outlives the temporary. > + // FIXME: Fold this into checkInitializerLifetime. > if (Args.size() == 1 && Args[0]->getType()->isArrayType() && > Entity.getType()->isPointerType() && > InitializedEntityOutlivesFullExpression(Entity)) { > @@ -7015,11 +7111,6 @@ 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()); > - > CheckForNullPointerDereference(S, CurInit.get()); > break; > > @@ -7036,10 +7127,6 @@ InitializationSequence::Perform(Sema &S, > 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 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 && > @@ -7490,10 +7577,6 @@ InitializationSequence::Perform(Sema &S, > // 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)) > @@ -7612,6 +7695,11 @@ InitializationSequence::Perform(Sema &S, > } > } > > + // Check whether the initializer has a shorter lifetime than the > initialized > + // entity, and if not, either lifetime-extend or warn as appropriate. > + if (auto *Init = CurInit.get()) > + S.checkInitializerLifetime(Entity, Init); > + > // Diagnose non-fatal problems with the completed initialization. > if (Entity.getKind() == InitializedEntity::EK_Member && > cast<FieldDecl>(Entity.getDecl())->isBitField()) > > Modified: cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp?rev=337627&r1=337626&r2=337627&view=diff > > ============================================================================== > --- cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp (original) > +++ cfe/trunk/test/Analysis/cxx-uninitialized-object-ptr-ref.cpp Fri Jul > 20 15:25:55 2018 > @@ -235,10 +235,10 @@ void fVoidPointerTest2() { > } > > class VoidPointerRRefTest1 { > - void *&&vptrrref; > + void *&&vptrrref; // expected-note {{here}} > > public: > - VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void > *&&>(vptr)) { > + VoidPointerRRefTest1(void *vptr, char) : vptrrref(static_cast<void > *&&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to > stack allocated parameter 'vptr'}} > // All good! > } > }; > @@ -249,10 +249,10 @@ void fVoidPointerRRefTest1() { > } > > class VoidPointerRRefTest2 { > - void **&&vpptrrref; > + void **&&vpptrrref; // expected-note {{here}} > > public: > - VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void > **&&>(vptr)) { > + VoidPointerRRefTest2(void **vptr, char) : vpptrrref(static_cast<void > **&&>(vptr)) { // expected-warning {{binding reference member 'vpptrrref' > to stack allocated parameter 'vptr'}} > // All good! > } > }; > @@ -263,10 +263,10 @@ void fVoidPointerRRefTest2() { > } > > class VoidPointerLRefTest { > - void *&vptrrref; > + void *&vptrrref; // expected-note {{here}} > > public: > - VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void > *&>(vptr)) { > + VoidPointerLRefTest(void *vptr, char) : vptrrref(static_cast<void > *&>(vptr)) { // expected-warning {{binding reference member 'vptrrref' to > stack allocated parameter 'vptr'}} > // All good! > } > }; > > 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=337627&r1=337626&r2=337627&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp > (original) > +++ cfe/trunk/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp Fri > Jul 20 15:25:55 2018 > @@ -72,18 +72,18 @@ std::initializer_list<int> thread_local > > // X86: @_ZN15partly_constant1kE = global i32 0, align 4 > // X86: @_ZN15partly_constant2ilE = global {{.*}} null, align 8 > -// X86: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = > internal global {{.*}} zeroinitializer, align 8 > -// X86: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = > internal global [3 x {{.*}}] zeroinitializer, align 8 > -// X86: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = > internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4 > -// X86: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = > internal global [2 x i32] zeroinitializer, align 4 > -// X86: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = > internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4 > +// X86: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE_]] = internal > global {{.*}} zeroinitializer, align 8 > +// X86: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE0_]] = > internal global [3 x {{.*}}] zeroinitializer, align 8 > +// X86: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE1_]] = > internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4 > +// X86: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE2_]] = > internal global [2 x i32] zeroinitializer, align 4 > +// X86: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE3_]] = > internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4 > // AMDGCN: @_ZN15partly_constant1kE = addrspace(1) global i32 0, align 4 > // AMDGCN: @_ZN15partly_constant2ilE = addrspace(4) global {{.*}} null, > align 8 > -// AMDGCN: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = > internal addrspace(4) global {{.*}} zeroinitializer, align 8 > -// AMDGCN: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = > internal addrspace(4) global [3 x {{.*}}] zeroinitializer, align 8 > -// AMDGCN: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = > internal addrspace(4) constant [3 x i32] [i32 1, i32 2, i32 3], align 4 > -// AMDGCN: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = > internal addrspace(4) global [2 x i32] zeroinitializer, align 4 > -// AMDGCN: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = > internal addrspace(4) constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], > align 4 > +// AMDGCN: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE_]] = > internal addrspace(4) global {{.*}} zeroinitializer, align 8 > +// AMDGCN: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE0_]] = > internal addrspace(4) global [3 x {{.*}}] zeroinitializer, align 8 > +// AMDGCN: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE1_]] = > internal addrspace(4) constant [3 x i32] [i32 1, i32 2, i32 3], align 4 > +// AMDGCN: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE2_]] = > internal addrspace(4) global [2 x i32] zeroinitializer, align 4 > +// AMDGCN: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE3_]] = > internal addrspace(4) constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], > align 4 > > // X86: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], > align 4 > // X86: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 > }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4 > @@ -375,7 +375,7 @@ namespace partly_constant { > // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]], > // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* > {{.*}}@[[PARTLY_CONSTANT_THIRD]]{{.*}}, i64 0, i64 0), > // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* > {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 2, i32 0) > - // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* > {{.*}}@_ZGRN15partly_constant2ilE4_{{.*}}, i64 0, i64 2, i32 1) > + // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* > {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 2, i32 1) > // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]], > // > // Outer init list. > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > -- Regards, Ilya Biryukov
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits