r337627 - Fold dangling-field warning into general initialization lifetime checks.
Ilya Biryukov via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 22 23:24:37 PDT 2018
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 at 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 at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
--
Regards,
Ilya Biryukov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180723/8f6e167a/attachment-0001.html>
More information about the cfe-commits
mailing list