r373159 - For P0784R7: compute whether a variable has constant destruction if it
Alex L via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 11 14:16:46 PST 2019
Hi Richard,
I have a question about this commit. It looks like it started emitting
`cxa_guard_acquire/release` calls in Objective-C code, for globals with
constant initializers, causing link failures for things that don't link
with libc++abi. Was that intentional? I'm still working on a reduced
test-case that I can post.
Thanks,
Alex
On Sat, 28 Sep 2019 at 22:06, Richard Smith via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: rsmith
> Date: Sat Sep 28 22:08:46 2019
> New Revision: 373159
>
> URL: http://llvm.org/viewvc/llvm-project?rev=373159&view=rev
> Log:
> For P0784R7: compute whether a variable has constant destruction if it
> has a constexpr destructor.
>
> For constexpr variables, reject if the variable does not have constant
> destruction. In all cases, do not emit runtime calls to the destructor
> for variables with constant destruction.
>
> Added:
> cfe/trunk/test/CXX/expr/expr.const/p6-2a.cpp
> cfe/trunk/test/CodeGenCXX/non-const-init-cxx2a.cpp
> Modified:
> cfe/trunk/include/clang/AST/Decl.h
> cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/lib/AST/ASTContext.cpp
> cfe/trunk/lib/AST/Decl.cpp
> cfe/trunk/lib/AST/ExprConstant.cpp
> cfe/trunk/lib/AST/Interp/Interp.cpp
> cfe/trunk/lib/AST/TextNodeDumper.cpp
> cfe/trunk/lib/CodeGen/CGCall.cpp
> cfe/trunk/lib/CodeGen/CGClass.cpp
> cfe/trunk/lib/CodeGen/CGDecl.cpp
> cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
> cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
> cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
> cfe/trunk/test/CodeGenCXX/attr-no-destroy-d54344.cpp
> cfe/trunk/test/CodeGenCXX/const-init-cxx2a.cpp
> cfe/trunk/test/CodeGenCXX/no_destroy.cpp
>
> Modified: cfe/trunk/include/clang/AST/Decl.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Decl.h (original)
> +++ cfe/trunk/include/clang/AST/Decl.h Sat Sep 28 22:08:46 2019
> @@ -808,12 +808,19 @@ struct EvaluatedStmt {
> /// valid if CheckedICE is true.
> bool IsICE : 1;
>
> + /// Whether this variable is known to have constant destruction. That
> is,
> + /// whether running the destructor on the initial value is a side-effect
> + /// (and doesn't inspect any state that might have changed during
> program
> + /// execution). This is currently only computed if the destructor is
> + /// non-trivial.
> + bool HasConstantDestruction : 1;
> +
> Stmt *Value;
> APValue Evaluated;
>
> - EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false),
> CheckedICE(false),
> - CheckingICE(false), IsICE(false) {}
> -
> + EvaluatedStmt()
> + : WasEvaluated(false), IsEvaluating(false), CheckedICE(false),
> + CheckingICE(false), IsICE(false), HasConstantDestruction(false) {}
> };
>
> /// Represents a variable declaration or definition.
> @@ -1267,6 +1274,14 @@ public:
> /// to untyped APValue if the value could not be evaluated.
> APValue *getEvaluatedValue() const;
>
> + /// Evaluate the destruction of this variable to determine if it
> constitutes
> + /// constant destruction.
> + ///
> + /// \pre isInitICE()
> + /// \return \c true if this variable has constant destruction, \c false
> if
> + /// not.
> + bool evaluateDestruction(SmallVectorImpl<PartialDiagnosticAt> &Notes)
> const;
> +
> /// Determines whether it is already known whether the
> /// initializer is an integral constant expression or not.
> bool isInitKnownICE() const;
> @@ -1505,9 +1520,14 @@ public:
> // has no definition within this source file.
> bool isKnownToBeDefined() const;
>
> - /// Do we need to emit an exit-time destructor for this variable?
> + /// Is destruction of this variable entirely suppressed? If so, the
> variable
> + /// need not have a usable destructor at all.
> bool isNoDestroy(const ASTContext &) const;
>
> + /// Do we need to emit an exit-time destructor for this variable, and
> if so,
> + /// what kind?
> + QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const;
> +
> // Implement isa/cast/dyncast/etc.
> static bool classof(const Decl *D) { return classofKind(D->getKind()); }
> static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar;
> }
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Sat Sep 28
> 22:08:46 2019
> @@ -145,8 +145,10 @@ def note_constexpr_access_volatile_obj :
> "a constant expression">;
> def note_constexpr_volatile_here : Note<
> "volatile %select{temporary created|object declared|member declared}0
> here">;
> -def note_constexpr_ltor_mutable : Note<
> - "read of mutable member %0 is not allowed in a constant expression">;
> +def note_constexpr_access_mutable : Note<
> + "%select{read of|read of|assignment to|increment of|decrement of|"
> + "member call on|dynamic_cast of|typeid applied to|destruction of}0 "
> + "mutable member %1 is not allowed in a constant expression">;
> def note_constexpr_ltor_non_const_int : Note<
> "read of non-const variable %0 is not allowed in a constant
> expression">;
> def note_constexpr_ltor_non_constexpr : Note<
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Sep 28
> 22:08:46 2019
> @@ -2384,6 +2384,8 @@ def err_constexpr_var_non_literal : Erro
> "constexpr variable cannot have non-literal type %0">;
> def err_constexpr_var_requires_const_init : Error<
> "constexpr variable %0 must be initialized by a constant expression">;
> +def err_constexpr_var_requires_const_destruction : Error<
> + "constexpr variable %0 must have constant destruction">;
> def err_constexpr_redecl_mismatch : Error<
> "%select{non-constexpr|constexpr|consteval}1 declaration of %0"
> " follows %select{non-constexpr|constexpr|consteval}2 declaration">;
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Sat Sep 28 22:08:46 2019
> @@ -10064,7 +10064,7 @@ bool ASTContext::DeclMustBeEmitted(const
> return false;
>
> // Variables that have destruction with side-effects are required.
> - if (VD->getType().isDestructedType())
> + if (VD->needsDestruction(*this))
> return true;
>
> // Variables that have initialization with side-effects are required.
>
> Modified: cfe/trunk/lib/AST/Decl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Decl.cpp (original)
> +++ cfe/trunk/lib/AST/Decl.cpp Sat Sep 28 22:08:46 2019
> @@ -2592,6 +2592,18 @@ bool VarDecl::isNoDestroy(const ASTConte
> !hasAttr<AlwaysDestroyAttr>()));
> }
>
> +QualType::DestructionKind
> +VarDecl::needsDestruction(const ASTContext &Ctx) const {
> + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
> + if (Eval->HasConstantDestruction)
> + return QualType::DK_none;
> +
> + if (isNoDestroy(Ctx))
> + return QualType::DK_none;
> +
> + return getType().isDestructedType();
> +}
> +
> MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
> if (isStaticDataMember())
> // FIXME: Remove ?
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Sat Sep 28 22:08:46 2019
> @@ -744,6 +744,15 @@ namespace {
> /// evaluated, if any.
> APValue::LValueBase EvaluatingDecl;
>
> + enum class EvaluatingDeclKind {
> + None,
> + /// We're evaluating the construction of EvaluatingDecl.
> + Ctor,
> + /// We're evaluating the destruction of EvaluatingDecl.
> + Dtor,
> + };
> + EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
> +
> /// EvaluatingDeclValue - This is the value being constructed for the
> /// declaration whose initializer is being evaluated, if any.
> APValue *EvaluatingDeclValue;
> @@ -902,8 +911,10 @@ namespace {
> discardCleanups();
> }
>
> - void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
> + void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
> + EvaluatingDeclKind EDK =
> EvaluatingDeclKind::Ctor) {
> EvaluatingDecl = Base;
> + IsEvaluatingDecl = EDK;
> EvaluatingDeclValue = &Value;
> }
>
> @@ -2913,8 +2924,8 @@ static bool isReadByLvalueToRvalueConver
>
> /// Diagnose an attempt to read from any unreadable field within the
> specified
> /// type, which might be a class type.
> -static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
> - QualType T) {
> +static bool diagnoseMutableFields(EvalInfo &Info, const Expr *E,
> AccessKinds AK,
> + QualType T) {
> CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
> if (!RD)
> return false;
> @@ -2929,17 +2940,17 @@ static bool diagnoseUnreadableFields(Eva
> // FIXME: Add core issue number for the union case.
> if (Field->isMutable() &&
> (RD->isUnion() ||
> isReadByLvalueToRvalueConversion(Field->getType()))) {
> - Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field;
> + Info.FFDiag(E, diag::note_constexpr_access_mutable, 1) << AK <<
> Field;
> Info.Note(Field->getLocation(), diag::note_declared_at);
> return true;
> }
>
> - if (diagnoseUnreadableFields(Info, E, Field->getType()))
> + if (diagnoseMutableFields(Info, E, AK, Field->getType()))
> return true;
> }
>
> for (auto &BaseSpec : RD->bases())
> - if (diagnoseUnreadableFields(Info, E, BaseSpec.getType()))
> + if (diagnoseMutableFields(Info, E, AK, BaseSpec.getType()))
> return true;
>
> // All mutable fields were empty, and thus not actually read.
> @@ -2947,7 +2958,8 @@ static bool diagnoseUnreadableFields(Eva
> }
>
> static bool lifetimeStartedInEvaluation(EvalInfo &Info,
> - APValue::LValueBase Base) {
> + APValue::LValueBase Base,
> + bool MutableSubobject = false) {
> // A temporary we created.
> if (Base.getCallIndex())
> return true;
> @@ -2956,19 +2968,42 @@ static bool lifetimeStartedInEvaluation(
> if (!Evaluating)
> return false;
>
> - // The variable whose initializer we're evaluating.
> - if (auto *BaseD = Base.dyn_cast<const ValueDecl*>())
> - if (declaresSameEntity(Evaluating, BaseD))
> - return true;
> + auto *BaseD = Base.dyn_cast<const ValueDecl*>();
>
> - // A temporary lifetime-extended by the variable whose initializer we're
> - // evaluating.
> - if (auto *BaseE = Base.dyn_cast<const Expr *>())
> - if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
> - if (declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating))
> - return true;
> + switch (Info.IsEvaluatingDecl) {
> + case EvalInfo::EvaluatingDeclKind::None:
> + return false;
>
> - return false;
> + case EvalInfo::EvaluatingDeclKind::Ctor:
> + // The variable whose initializer we're evaluating.
> + if (BaseD)
> + return declaresSameEntity(Evaluating, BaseD);
> +
> + // A temporary lifetime-extended by the variable whose initializer
> we're
> + // evaluating.
> + if (auto *BaseE = Base.dyn_cast<const Expr *>())
> + if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
> + return declaresSameEntity(BaseMTE->getExtendingDecl(),
> Evaluating);
> + return false;
> +
> + case EvalInfo::EvaluatingDeclKind::Dtor:
> + // C++2a [expr.const]p6:
> + // [during constant destruction] the lifetime of a and its
> non-mutable
> + // subobjects (but not its mutable subobjects) [are] considered to
> start
> + // within e.
> + //
> + // FIXME: We can meaningfully extend this to cover non-const objects,
> but
> + // we will need special handling: we should be able to access only
> + // subobjects of such objects that are themselves declared const.
> + if (!BaseD ||
> + !(BaseD->getType().isConstQualified() ||
> + BaseD->getType()->isReferenceType()) ||
> + MutableSubobject)
> + return false;
> + return declaresSameEntity(Evaluating, BaseD);
> + }
> +
> + llvm_unreachable("unknown evaluating decl kind");
> }
>
> namespace {
> @@ -2986,13 +3021,13 @@ struct CompleteObject {
> CompleteObject(APValue::LValueBase Base, APValue *Value, QualType Type)
> : Base(Base), Value(Value), Type(Type) {}
>
> - bool mayReadMutableMembers(EvalInfo &Info) const {
> + bool mayAccessMutableMembers(EvalInfo &Info, AccessKinds AK) const {
> // In C++14 onwards, it is permitted to read a mutable member whose
> // lifetime began within the evaluation.
> // FIXME: Should we also allow this in C++11?
> if (!Info.getLangOpts().CPlusPlus14)
> return false;
> - return lifetimeStartedInEvaluation(Info, Base);
> + return lifetimeStartedInEvaluation(Info, Base,
> /*MutableSubobject*/true);
> }
>
> explicit operator bool() const { return !Type.isNull(); }
> @@ -3097,9 +3132,9 @@ findSubobject(EvalInfo &Info, const Expr
> // things we need to check: if there are any mutable subobjects, we
> // cannot perform this read. (This only happens when performing a
> trivial
> // copy or assignment.)
> - if (ObjType->isRecordType() && isRead(handler.AccessKind) &&
> - !Obj.mayReadMutableMembers(Info) &&
> - diagnoseUnreadableFields(Info, E, ObjType))
> + if (ObjType->isRecordType() &&
> + !Obj.mayAccessMutableMembers(Info, handler.AccessKind) &&
> + diagnoseMutableFields(Info, E, handler.AccessKind, ObjType))
> return handler.failed();
> }
>
> @@ -3167,10 +3202,10 @@ findSubobject(EvalInfo &Info, const Expr
> : O->getComplexFloatReal(), ObjType);
> }
> } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
> - if (Field->isMutable() && isRead(handler.AccessKind) &&
> - !Obj.mayReadMutableMembers(Info)) {
> - Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1)
> - << Field;
> + if (Field->isMutable() &&
> + !Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
> + Info.FFDiag(E, diag::note_constexpr_access_mutable, 1)
> + << handler.AccessKind << Field;
> Info.Note(Field->getLocation(), diag::note_declared_at);
> return handler.failed();
> }
> @@ -3427,8 +3462,7 @@ static CompleteObject findCompleteObject
> // the variable we're reading must be const.
> if (!Frame) {
> if (Info.getLangOpts().CPlusPlus14 &&
> - declaresSameEntity(
> - VD, Info.EvaluatingDecl.dyn_cast<const ValueDecl *>())) {
> + lifetimeStartedInEvaluation(Info, LVal.Base)) {
> // OK, we can read and modify an object if we're in the process of
> // evaluating its initializer, because its lifetime began in this
> // evaluation.
> @@ -3518,11 +3552,14 @@ static CompleteObject findCompleteObject
> // int x = ++r;
> // constexpr int k = r;
> // Therefore we use the C++14 rules in C++11 too.
> - const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const
> ValueDecl*>();
> - const ValueDecl *ED = MTE->getExtendingDecl();
> + //
> + // Note that temporaries whose lifetimes began while evaluating a
> + // variable's constructor are not usable while evaluating the
> + // corresponding destructor, not even if they're of
> const-qualified
> + // types.
> if (!(BaseType.isConstQualified() &&
> BaseType->isIntegralOrEnumerationType()) &&
> - !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
> + !lifetimeStartedInEvaluation(Info, LVal.Base)) {
> if (!IsAccess)
> return CompleteObject(LVal.getLValueBase(), nullptr,
> BaseType);
> Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1)
> << AK;
> @@ -13282,6 +13319,41 @@ bool Expr::EvaluateAsInitializer(APValue
> CheckMemoryLeaks(Info);
> }
>
> +bool VarDecl::evaluateDestruction(
> + SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
> + assert(getEvaluatedValue() && !getEvaluatedValue()->isAbsent() &&
> + "cannot evaluate destruction of non-constant-initialized
> variable");
> +
> + Expr::EvalStatus EStatus;
> + EStatus.Diag = &Notes;
> +
> + // Make a copy of the value for the destructor to mutate.
> + APValue DestroyedValue = *getEvaluatedValue();
> +
> + EvalInfo Info(getASTContext(), EStatus,
> EvalInfo::EM_ConstantExpression);
> + Info.setEvaluatingDecl(this, DestroyedValue,
> + EvalInfo::EvaluatingDeclKind::Dtor);
> + Info.InConstantContext = true;
> +
> + SourceLocation DeclLoc = getLocation();
> + QualType DeclTy = getType();
> +
> + LValue LVal;
> + LVal.set(this);
> +
> + // FIXME: Consider storing whether this variable has constant
> destruction in
> + // the EvaluatedStmt so that CodeGen can query it.
> + if (!HandleDestruction(Info, DeclLoc, LVal.Base, DestroyedValue,
> DeclTy) ||
> + EStatus.HasSideEffects)
> + return false;
> +
> + if (!Info.discardCleanups())
> + llvm_unreachable("Unhandled cleanup; missing full expression
> marker?");
> +
> + ensureEvaluatedStmt()->HasConstantDestruction = true;
> + return true;
> +}
> +
> /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
> /// constant folded, but discard the result.
> bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK)
> const {
>
> Modified: cfe/trunk/lib/AST/Interp/Interp.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Interp/Interp.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Interp/Interp.cpp (original)
> +++ cfe/trunk/lib/AST/Interp/Interp.cpp Sat Sep 28 22:08:46 2019
> @@ -275,7 +275,7 @@ bool CheckMutable(InterpState &S, CodePt
>
> const SourceInfo &Loc = S.Current->getSource(OpPC);
> const FieldDecl *Field = Ptr.getField();
> - S.FFDiag(Loc, diag::note_constexpr_ltor_mutable, 1) << Field;
> + S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read <<
> Field;
> S.Note(Field->getLocation(), diag::note_declared_at);
> return false;
> }
>
> Modified: cfe/trunk/lib/AST/TextNodeDumper.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TextNodeDumper.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/TextNodeDumper.cpp (original)
> +++ cfe/trunk/lib/AST/TextNodeDumper.cpp Sat Sep 28 22:08:46 2019
> @@ -1384,6 +1384,8 @@ void TextNodeDumper::VisitVarDecl(const
> break;
> }
> }
> + if (D->needsDestruction(D->getASTContext()))
> + OS << " destroyed";
> if (D->isParameterPack())
> OS << " pack";
> }
>
> Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGCall.cpp Sat Sep 28 22:08:46 2019
> @@ -3093,7 +3093,7 @@ void CodeGenFunction::EmitDelegateCallAr
> // Deactivate the cleanup for the callee-destructed param that was
> pushed.
> if (hasAggregateEvaluationKind(type) && !CurFuncIsThunk &&
> type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee() &&
> - type.isDestructedType()) {
> + param->needsDestruction(getContext())) {
> EHScopeStack::stable_iterator cleanup =
> CalleeDestructedParamCleanups.lookup(cast<ParmVarDecl>(param));
> assert(cleanup.isValid() &&
>
> Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGClass.cpp Sat Sep 28 22:08:46 2019
> @@ -2083,7 +2083,7 @@ static bool canEmitDelegateCallArgs(Code
> if (CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
> // If the parameters are callee-cleanup, it's not safe to forward.
> for (auto *P : Ctor->parameters())
> - if (P->getType().isDestructedType())
> + if (P->needsDestruction(CGF.getContext()))
> return false;
>
> // Likewise if they're inalloca.
>
> Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Sat Sep 28 22:08:46 2019
> @@ -305,14 +305,6 @@ llvm::Constant *CodeGenModule::getOrCrea
> return Addr;
> }
>
> -/// hasNontrivialDestruction - Determine whether a type's destruction is
> -/// non-trivial. If so, and the variable uses static initialization, we
> must
> -/// register its destructor to run on exit.
> -static bool hasNontrivialDestruction(QualType T) {
> - CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
> - return RD && !RD->hasTrivialDestructor();
> -}
> -
> /// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
> /// global variable that has already been created for it. If the
> initializer
> /// has a different type than GV does, this may free GV and return a
> different
> @@ -372,7 +364,7 @@ CodeGenFunction::AddInitializerToStaticV
>
> emitter.finalize(GV);
>
> - if (hasNontrivialDestruction(D.getType()) && HaveInsertPoint()) {
> + if (D.needsDestruction(getContext()) && HaveInsertPoint()) {
> // We have a constant initializer, but a nontrivial destructor. We
> still
> // need to perform a guarded "initialization" in order to register the
> // destructor.
> @@ -1994,7 +1986,7 @@ void CodeGenFunction::EmitAutoVarCleanup
> const VarDecl &D = *emission.Variable;
>
> // Check the type for a cleanup.
> - if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
> + if (QualType::DestructionKind dtorKind =
> D.needsDestruction(getContext()))
> emitAutoVarTypeCleanup(emission, dtorKind);
>
> // In GC mode, honor objc_precise_lifetime.
> @@ -2404,7 +2396,8 @@ void CodeGenFunction::EmitParmDecl(const
> // cleanup.
> if (hasAggregateEvaluationKind(Ty) && !CurFuncIsThunk &&
> Ty->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
> - if (QualType::DestructionKind DtorKind = Ty.isDestructedType()) {
> + if (QualType::DestructionKind DtorKind =
> + D.needsDestruction(getContext())) {
> assert((DtorKind == QualType::DK_cxx_destructor ||
> DtorKind == QualType::DK_nontrivial_c_struct) &&
> "unexpected destructor type");
>
> Modified: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDeclCXX.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Sat Sep 28 22:08:46 2019
> @@ -73,16 +73,10 @@ static void EmitDeclDestroy(CodeGenFunct
> // that isn't balanced out by a destructor call as intended by the
> // attribute. This also checks for -fno-c++-static-destructors and
> // bails even if the attribute is not present.
> - if (D.isNoDestroy(CGF.getContext()))
> - return;
> -
> - CodeGenModule &CGM = CGF.CGM;
> + QualType::DestructionKind DtorKind =
> D.needsDestruction(CGF.getContext());
>
> // FIXME: __attribute__((cleanup)) ?
>
> - QualType Type = D.getType();
> - QualType::DestructionKind DtorKind = Type.isDestructedType();
> -
> switch (DtorKind) {
> case QualType::DK_none:
> return;
> @@ -101,6 +95,9 @@ static void EmitDeclDestroy(CodeGenFunct
> llvm::FunctionCallee Func;
> llvm::Constant *Argument;
>
> + CodeGenModule &CGM = CGF.CGM;
> + QualType Type = D.getType();
> +
> // Special-case non-array C++ destructors, if they have the right
> signature.
> // Under some ABIs, destructors return this instead of void, and cannot
> be
> // passed directly to __cxa_atexit if the target does not allow this
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Sat Sep 28 22:08:46 2019
> @@ -3809,9 +3809,9 @@ void CodeGenModule::EmitGlobalVarDefinit
> return;
>
> llvm::Constant *Init = nullptr;
> - CXXRecordDecl *RD =
> ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
> bool NeedsGlobalCtor = false;
> - bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor();
> + bool NeedsGlobalDtor =
> + D->needsDestruction(getContext()) == QualType::DK_cxx_destructor;
>
> const VarDecl *InitDecl;
> const Expr *InitExpr = D->getAnyInitializer(InitDecl);
>
> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sat Sep 28 22:08:46 2019
> @@ -350,7 +350,7 @@ public:
> // If we have the only definition, we don't need a thread wrapper if
> we
> // will emit the value as a constant.
> if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD)))
> - return !VD->getType().isDestructedType() &&
> InitDecl->evaluateValue();
> + return !VD->needsDestruction(getContext()) &&
> InitDecl->evaluateValue();
>
> // Otherwise, we need a thread wrapper unless we know that every
> // translation unit will emit the value as a constant. We rely on
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Sep 28 22:08:46 2019
> @@ -13398,6 +13398,19 @@ void Sema::FinalizeVarWithDestructor(Var
> }
>
> if (Destructor->isTrivial()) return;
> +
> + // If the destructor is constexpr, check whether the variable has
> constant
> + // destruction now.
> + if (Destructor->isConstexpr() && VD->evaluateValue()) {
> + SmallVector<PartialDiagnosticAt, 8> Notes;
> + if (!VD->evaluateDestruction(Notes) && VD->isConstexpr()) {
> + Diag(VD->getLocation(),
> + diag::err_constexpr_var_requires_const_destruction) << VD;
> + for (unsigned I = 0, N = Notes.size(); I != N; ++I)
> + Diag(Notes[I].first, Notes[I].second);
> + }
> + }
> +
> if (!VD->hasGlobalStorage()) return;
>
> // Emit warning for non-trivial dtor in global scope (a real global,
>
> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Sat Sep 28 22:08:46 2019
> @@ -1390,10 +1390,11 @@ ASTDeclReader::RedeclarableResult ASTDec
>
> if (uint64_t Val = Record.readInt()) {
> VD->setInit(Record.readExpr());
> - if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3
> + if (Val > 1) {
> EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
> Eval->CheckedICE = true;
> - Eval->IsICE = Val == 3;
> + Eval->IsICE = (Val & 1) != 0;
> + Eval->HasConstantDestruction = (Val & 4) != 0;
> }
> }
>
>
> Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Sat Sep 28 22:08:46 2019
> @@ -968,7 +968,14 @@ void ASTDeclWriter::VisitVarDecl(VarDecl
> Record.push_back(D->getLinkageInternal());
>
> if (D->getInit()) {
> - Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
> + if (!D->isInitKnownICE())
> + Record.push_back(1);
> + else {
> + Record.push_back(
> + 2 |
> + (D->isInitICE() ? 1 : 0) |
> + (D->ensureEvaluatedStmt()->HasConstantDestruction ? 4 : 0));
> + }
> Record.AddStmt(D->getInit());
> } else {
> Record.push_back(0);
> @@ -2140,7 +2147,7 @@ void ASTWriter::WriteDeclAbbrevs() {
> Abv->Add(BitCodeAbbrevOp(0)); //
> ImplicitParamKind
> Abv->Add(BitCodeAbbrevOp(0)); // EscapingByref
> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
> - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // IsInitICE
> (local)
> + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // IsInitICE
> (local)
> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local
> enum)
> // Type Source Info
> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
>
> Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp Sat Sep 28
> 22:08:46 2019
> @@ -1,4 +1,5 @@
> // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
> +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
>
> // A constexpr specifier used in an object declaration declares the
> object as
> // const.
> @@ -35,3 +36,19 @@ struct pixel {
> };
> constexpr pixel ur = { 1294, 1024 }; // ok
> constexpr pixel origin; // expected-error {{default
> initialization of an object of const type 'const pixel' without a
> user-provided default constructor}}
> +
> +#if __cplusplus > 201702L
> +// A constexpr variable shall have constant destruction.
> +struct A {
> + bool ok;
> + constexpr A(bool ok) : ok(ok) {}
> + constexpr ~A() noexcept(false) {
> + void oops(); // expected-note 2{{declared here}}
> + if (!ok) oops(); // expected-note 2{{non-constexpr function}}
> + }
> +};
> +
> +constexpr A const_dtor(true);
> +constexpr A non_const_dtor(false); // expected-error {{must have constant
> destruction}} expected-note {{in call}}
> +constexpr A arr_dtor[5] = {true, true, true, false, true}; //
> expected-error {{must have constant destruction}} expected-note {{in call
> to '&arr_dtor[3]->~A()'}}
> +#endif
>
> Added: cfe/trunk/test/CXX/expr/expr.const/p6-2a.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p6-2a.cpp?rev=373159&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CXX/expr/expr.const/p6-2a.cpp (added)
> +++ cfe/trunk/test/CXX/expr/expr.const/p6-2a.cpp Sat Sep 28 22:08:46 2019
> @@ -0,0 +1,43 @@
> +// RUN: %clang_cc1 -std=c++2a -verify %s
> +
> +constexpr int non_class = 42;
> +constexpr int arr_non_class[5] = {1, 2, 3};
> +
> +struct A {
> + int member = 1;
> + constexpr ~A() { member = member + 1; }
> +};
> +constexpr A class_ = {};
> +constexpr A arr_class[5] = {{}, {}};
> +
> +struct Mutable {
> + mutable int member = 1; // expected-note {{declared here}}
> + constexpr ~Mutable() { member = member + 1; } // expected-note {{read
> of mutable member}}
> +};
> +constexpr Mutable mut_member; // expected-error {{must have constant
> destruction}} expected-note {{in call}}
> +
> +struct MutableStore {
> + mutable int member = 1; // expected-note {{declared here}}
> + constexpr ~MutableStore() { member = 2; } // expected-note {{assignment
> to mutable member}}
> +};
> +constexpr MutableStore mut_store; // expected-error {{must have constant
> destruction}} expected-note {{in call}}
> +
> +// Note: the constant destruction rules disallow this example even though
> hcm.n is a const object.
> +struct MutableConst {
> + struct HasConstMember {
> + const int n = 4;
> + };
> + mutable HasConstMember hcm; // expected-note {{here}}
> + constexpr ~MutableConst() {
> + int q = hcm.n; // expected-note {{read of mutable}}
> + }
> +};
> +constexpr MutableConst mc; // expected-error {{must have constant
> destruction}} expected-note {{in call}}
> +
> +struct Temporary {
> + int &&temp;
> + constexpr ~Temporary() {
> + int n = temp; // expected-note {{outside the expression that created
> the temporary}}
> + }
> +};
> +constexpr Temporary t = {3}; // expected-error {{must have constant
> destruction}} expected-note {{created here}} expected-note {{in call}}
>
> Modified: cfe/trunk/test/CodeGenCXX/attr-no-destroy-d54344.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-no-destroy-d54344.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/attr-no-destroy-d54344.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/attr-no-destroy-d54344.cpp Sat Sep 28
> 22:08:46 2019
> @@ -14,6 +14,7 @@
>
> class a {
> public:
> + a();
> ~a();
> };
> class logger_base {
>
> Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx2a.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx2a.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/const-init-cxx2a.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/const-init-cxx2a.cpp Sat Sep 28 22:08:46 2019
> @@ -1,5 +1,58 @@
> -// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s
> -std=c++2a | FileCheck %s
> -// expected-no-diagnostics
> +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -std=c++2a
> | FileCheck %s --implicit-check-not=cxx_global_var_init
> --implicit-check-not=cxa_atexit
> +
> +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-pch -o %t.pch %s
> -std=c++2a
> +// RUN: %clang_cc1 -triple x86_64-linux-gnu -include-pch %t.pch -x c++
> /dev/null -emit-llvm -o - -std=c++2a | FileCheck %s
> --implicit-check-not=cxx_global_var_init --implicit-check-not=cxa_atexit
>
> // CHECK: @a = global i32 123,
> int a = (delete new int, 123);
> +
> +struct B {
> + constexpr B() {}
> + constexpr ~B() { n *= 5; }
> + int n = 123;
> +};
> +// CHECK: @b = global {{.*}} i32 123
> +extern constexpr B b = B();
> +
> +// CHECK: @_ZL1c = internal global {{.*}} i32 123
> +const B c;
> +int use_c() { return c.n; }
> +
> +struct D {
> + int n;
> + constexpr ~D() {}
> +};
> +D d;
> +// CHECK: @d = global {{.*}} zeroinitializer
> +
> +D d_arr[3];
> +// CHECK: @d_arr = global {{.*}} zeroinitializer
> +
> +thread_local D d_tl;
> +// CHECK: @d_tl = thread_local global {{.*}} zeroinitializer
> +
> +// CHECK-NOT: @llvm.global_ctors
> +
> +// CHECK-LABEL: define {{.*}} @_Z1fv(
> +void f() {
> + // CHECK-NOT: call
> + // CHECK: call {{.*}}memcpy
> + // CHECK-NOT: call
> + // CHECK: call {{.*}}memset
> + // CHECK-NOT: call
> + // CHECK: }
> + constexpr B b;
> + D d = D();
> +}
> +
> +// CHECK-LABEL: define {{.*}} @_Z1gv(
> +void g() {
> + // CHECK-NOT: call
> + // CHECK-NOT: cxa_guard
> + // CHECK-NOT: _ZGV
> + // CHECK: }
> + static constexpr B b1;
> + static const B b2;
> + static D d;
> + thread_local D d_tl;
> +}
>
> Modified: cfe/trunk/test/CodeGenCXX/no_destroy.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/no_destroy.cpp?rev=373159&r1=373158&r2=373159&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/no_destroy.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/no_destroy.cpp Sat Sep 28 22:08:46 2019
> @@ -5,10 +5,8 @@ struct NonTrivial {
> ~NonTrivial();
> };
>
> -// CHECK-LABEL: define internal void @__cxx_global_var_init
> // CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev
> [[clang::no_destroy]] NonTrivial nt1;
> -// CHECK-LABEL: define internal void @__cxx_global_var_init
> // CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev
> [[clang::no_destroy]] thread_local NonTrivial nt2;
>
> @@ -16,11 +14,9 @@ struct NonTrivial2 {
> ~NonTrivial2();
> };
>
> -// CHECK-LABEL: define internal void @__cxx_global_var_init
> -// CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev
> +// CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev{{.*}}nt21
> NonTrivial2 nt21;
> -// CHECK-LABEL: define internal void @__cxx_global_var_init
> -// CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev
> +// CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev{{.*}}nt22
> thread_local NonTrivial2 nt22;
>
> // CHECK-LABEL: define void @_Z1fv
>
> Added: cfe/trunk/test/CodeGenCXX/non-const-init-cxx2a.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/non-const-init-cxx2a.cpp?rev=373159&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/non-const-init-cxx2a.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/non-const-init-cxx2a.cpp Sat Sep 28 22:08:46
> 2019
> @@ -0,0 +1,19 @@
> +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s
> -std=c++2a | FileCheck %s
> +
> +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-pch -o %t.pch %s
> -std=c++2a
> +// RUN: %clang_cc1 -triple x86_64-apple-darwin -include-pch %t.pch -x c++
> /dev/null -emit-llvm -o - -std=c++2a | FileCheck %s
> +
> +struct B {
> + constexpr B() {}
> + constexpr ~B() { n *= 5; }
> + int n = 123;
> +};
> +
> +// We emit a dynamic destructor here because b.n might have been modified
> +// before b is destroyed.
> +//
> +// CHECK: @b = global {{.*}} i32 123
> +B b = B();
> +
> +// CHECK: define {{.*}}cxx_global_var_init
> +// CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://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/20191111/6965fbf7/attachment-0001.html>
More information about the cfe-commits
mailing list