r337627 - Fold dangling-field warning into general initialization lifetime checks.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 23 14:19:57 PDT 2018
Thanks, fixed and re-committed in r337726.
On Sun, 22 Jul 2018 at 23:33, Ilya Biryukov via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Reverted in r337671
>
> On Mon, Jul 23, 2018 at 8:24 AM Ilya Biryukov <ibiryukov at 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 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
>>
>
>
> --
> Regards,
> Ilya Biryukov
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180723/64232671/attachment-0001.html>
More information about the cfe-commits
mailing list