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