r373159 - For P0784R7: compute whether a variable has constant destruction if it
Alex L via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 8 13:17:04 PST 2020
Hi Richard,
I posted a patch that partially reverts your commit:
https://reviews.llvm.org/D72411. Unfortunately I can't revert it fully.
Thanks,
Alex
On Mon, 11 Nov 2019 at 15:30, Alex L <arphaman at gmail.com> wrote:
> Here's a reduced test case.
>
> ```
> // OPTIONS: -x objective-c -std=gnu99 -fobjc-arc -emit-llvm
> @interface Foo
> @end
>
> Foo *foo() {
> static Foo *f = ((void*)0;
> return f;
> }
> // CHECK-NOT: cxa_guard
> ```
>
> AFAIK clang should not emit C++ guard variables in non-C++ code. Is that
> correct?
>
> On Mon, 11 Nov 2019 at 14:16, Alex L <arphaman at gmail.com> wrote:
>
>> 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/20200108/844837c9/attachment-0001.html>
More information about the cfe-commits
mailing list