Thanks, fixed and re-committed in r337726. On Sun, 22 Jul 2018 at 23:33, Ilya Biryukov via cfe-commits < cfe-commits@lists.llvm.org> wrote:
> 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 >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits