Reverted in r337671 On Mon, Jul 23, 2018 at 8:24 AM Ilya Biryukov <ibiryu...@google.com> wrote:
> 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 > -- Regards, Ilya Biryukov
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits