diff options
-rw-r--r-- | lib/AST/ExprConstant.cpp | 17 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 20 | ||||
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 27 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 9 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 18 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 5 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 16 | ||||
-rw-r--r-- | test/CXX/class/class.static/class.static.data/p3.cpp | 6 | ||||
-rw-r--r-- | test/CodeGenCXX/const-init-cxx11.cpp | 84 |
13 files changed, 179 insertions, 46 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 520e3cbbaf..c0fff5e478 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -855,7 +855,8 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E); static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info, const LValue &This, const Expr *E, CheckConstantExpressionKind CCEK - = CCEK_Constant); + = CCEK_Constant, + bool AllowNonLiteralTypes = false); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result, @@ -5829,8 +5830,9 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) { /// which were initialized earlier. static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info, const LValue &This, const Expr *E, - CheckConstantExpressionKind CCEK) { - if (!CheckLiteralType(Info, E)) + CheckConstantExpressionKind CCEK, + bool AllowNonLiteralTypes) { + if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E)) return false; if (E->isRValue()) { @@ -5941,9 +5943,6 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, EvalInfo InitInfo(Ctx, EStatus); InitInfo.setEvaluatingDecl(VD, Value); - if (!CheckLiteralType(InitInfo, this)) - return false; - LValue LVal; LVal.set(VD); @@ -5954,11 +5953,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, if (Ctx.getLangOptions().CPlusPlus && !VD->hasLocalStorage() && !VD->getType()->isReferenceType()) { ImplicitValueInitExpr VIE(VD->getType()); - if (!EvaluateConstantExpression(Value, InitInfo, LVal, &VIE)) + if (!EvaluateConstantExpression(Value, InitInfo, LVal, &VIE, CCEK_Constant, + /*AllowNonLiteralTypes=*/true)) return false; } - return EvaluateConstantExpression(Value, InitInfo, LVal, this) && + return EvaluateConstantExpression(Value, InitInfo, LVal, this, CCEK_Constant, + /*AllowNonLiteralTypes=*/true) && !EStatus.HasSideEffects; } diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index c1b20af799..e5d3f2da6b 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -168,6 +168,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *GV) { + llvm::GlobalVariable *GV, + bool PerformInit) { ErrorUnsupportedABI(CGF, "static local variable initialization"); } diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 5e21bb0c9f..4bacd01403 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -226,12 +226,14 @@ public: /// Emits the guarded initializer and destructor setup for the given /// variable, given that it couldn't be emitted as a constant. + /// If \p PerformInit is false, the initialization has been folded to a + /// constant and should not be performed. /// /// The variable may be: /// - a static local variable /// - a static data member of a class template instantiation virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr); + llvm::GlobalVariable *DeclPtr, bool PerformInit); }; diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 3d32091a4b..2de19840e5 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -196,6 +196,14 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, return GV; } +/// 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 @@ -215,7 +223,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, // be constant. GV->setConstant(false); - EmitCXXGuardedInit(D, GV); + EmitCXXGuardedInit(D, GV, /*PerformInit*/true); } return GV; } @@ -248,6 +256,16 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, } GV->setInitializer(Init); + + if (hasNontrivialDestruction(D.getType())) { + // We have a constant initializer, but a nontrivial destructor. We still + // need to perform a guarded "initialization" in order to register the + // destructor. Since we're running a destructor on this variable, it can't + // be a constant even if it's const. + GV->setConstant(false); + EmitCXXGuardedInit(D, GV, /*PerformInit*/false); + } + return GV; } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 8406002e5a..44acf62aa6 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -102,17 +102,21 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, } void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, - llvm::Constant *DeclPtr) { + llvm::Constant *DeclPtr, + bool PerformInit) { const Expr *Init = D.getInit(); QualType T = D.getType(); if (!T->isReferenceType()) { - EmitDeclInit(*this, D, DeclPtr); + if (PerformInit) + EmitDeclInit(*this, D, DeclPtr); EmitDeclDestroy(*this, D, DeclPtr); return; } + assert(PerformInit && "cannot have constant initializer which needs " + "destruction for reference"); unsigned Alignment = getContext().getDeclAlign(&D).getQuantity(); RValue RV = EmitReferenceBindingToExpr(Init, &D); EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T); @@ -152,7 +156,8 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, } void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, - llvm::GlobalVariable *DeclPtr) { + llvm::GlobalVariable *DeclPtr, + bool PerformInit) { // If we've been asked to forbid guard variables, emit an error now. // This diagnostic is hard-coded for Darwin's use case; we can find // better phrasing if someone else needs it. @@ -161,7 +166,7 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, "this initialization requires a guard variable, which " "the kernel does not support"); - CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr); + CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit); } static llvm::Function * @@ -186,14 +191,16 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, void CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, - llvm::GlobalVariable *Addr) { + llvm::GlobalVariable *Addr, + bool PerformInit) { llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); // Create a variable initialization function. llvm::Function *Fn = CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init"); - CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr); + CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, + PerformInit); if (D->hasAttr<InitPriorityAttr>()) { unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority(); @@ -267,7 +274,8 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() { /// Emit the code necessary to initialize the given global variable. void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, - llvm::GlobalVariable *Addr) { + llvm::GlobalVariable *Addr, + bool PerformInit) { StartFunction(GlobalDecl(), getContext().VoidTy, Fn, getTypes().getNullaryFunctionInfo(), FunctionArgList(), SourceLocation()); @@ -277,9 +285,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, // definitions explicitly marked weak. if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage || Addr->getLinkage() == llvm::GlobalValue::WeakAnyLinkage) { - EmitCXXGuardedInit(*D, Addr); + EmitCXXGuardedInit(*D, Addr, PerformInit); } else { - EmitCXXGlobalVarDeclInit(*D, Addr); + EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit); } FinishFunction(); @@ -357,4 +365,3 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr, return fn; } - diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index ccb4b930e6..0b3ac9cbe5 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -939,6 +939,15 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D, if (const APValue *Value = D.evaluateValue()) return EmitConstantValue(*Value, D.getType(), CGF); + // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a + // reference is a constant expression, and the reference binds to a temporary, + // then constant initialization is performed. ConstExprEmitter will + // incorrectly emit a prvalue constant in this case, and the calling code + // interprets that as the (pointer) value of the reference, rather than the + // desired value of the referee. + if (D.getType()->isReferenceType()) + return 0; + const Expr *E = D.getInit(); assert(E && "No initializer to emit"); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 277640b8ce..ca5b88363e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2361,7 +2361,8 @@ public: /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ /// variable with global storage. - void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr); + void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr, + bool PerformInit); /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr /// with the C++ runtime so that its destructor will be called at exit. @@ -2373,7 +2374,8 @@ public: /// possible to prove that an initialization will be done exactly /// once, e.g. with a static local variable or a static data member /// of a class template. - void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr); + void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr, + bool PerformInit); /// GenerateCXXGlobalInitFunc - Generates code for initializing global /// variables. @@ -2389,7 +2391,8 @@ public: void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, - llvm::GlobalVariable *Addr); + llvm::GlobalVariable *Addr, + bool PerformInit); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index fde217efec..2ebea59264 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1359,7 +1359,9 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); - bool NonConstInit = false; + CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + bool NeedsGlobalCtor = false; + bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor(); const VarDecl *InitDecl; const Expr *InitExpr = D->getAnyInitializer(InitDecl); @@ -1385,15 +1387,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { if (getLangOptions().CPlusPlus) { Init = EmitNullConstant(T); - NonConstInit = true; + NeedsGlobalCtor = true; } else { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); } } else { // We don't need an initializer, so remove the entry for the delayed - // initializer position (just in case this entry was delayed). - if (getLangOptions().CPlusPlus) + // initializer position (just in case this entry was delayed) if we + // also don't need to register a destructor. + if (getLangOptions().CPlusPlus && !NeedsGlobalDtor) DelayedCXXInitPosition.erase(D); } } @@ -1448,7 +1451,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); - if (!NonConstInit && DeclIsConstantGlobal(Context, D, true)) + if (!NeedsGlobalCtor && !NeedsGlobalDtor && + DeclIsConstantGlobal(Context, D, true)) GV->setConstant(true); GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); @@ -1464,8 +1468,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { SetCommonAttributes(D, GV); // Emit the initializer function if necessary. - if (NonConstInit) - EmitCXXGlobalVarDeclInitFunc(D, GV); + if (NeedsGlobalCtor || NeedsGlobalDtor) + EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 08e1ed7fb1..6813edd5f1 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -900,8 +900,11 @@ private: /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals. void EmitCXXGlobalDtorFunc(); + /// EmitCXXGlobalVarDeclInitFunc - Emit the function that initializes the + /// specified global (if PerformInit is true) and registers its destructor. void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, - llvm::GlobalVariable *Addr); + llvm::GlobalVariable *Addr, + bool PerformInit); // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 044b7f0532..8dee17a38c 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -121,7 +121,7 @@ public: llvm::Value *&AllocPtr, CharUnits &CookieSize); void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr); + llvm::GlobalVariable *DeclPtr, bool PerformInit); }; class ARMCXXABI : public ItaniumCXXABI { @@ -1016,7 +1016,8 @@ namespace { /// just special-case it at particular places. void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *GV) { + llvm::GlobalVariable *GV, + bool PerformInit) { CGBuilderTy &Builder = CGF.Builder; // We only need to use thread-safe statics for local variables; @@ -1129,7 +1130,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, } // Emit the initializer and add a global destructor if appropriate. - CGF.EmitCXXGlobalVarDeclInit(D, GV); + CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit); if (threadsafe) { // Pop the guard-abort cleanup if we pushed one. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3c73f689e7..de9feccaf3 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3991,15 +3991,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateParamLists.release()); } - if (D.getDeclSpec().isConstexprSpecified()) { + if (D.getDeclSpec().isConstexprSpecified()) NewVD->setConstexpr(true); - SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc(); - if (!NewVD->isInvalidDecl() && !R->isDependentType() && - RequireLiteralType(NewVD->getLocation(), R, - PDiag(diag::err_constexpr_var_non_literal) - << SourceRange(ConstexprLoc))) - NewVD->setInvalidDecl(); - } } // Set the lexical context. If the declarator has a C++ scope specifier, the @@ -4347,6 +4340,13 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, return false; } + if (NewVD->isConstexpr() && !T->isDependentType() && + RequireLiteralType(NewVD->getLocation(), T, + PDiag(diag::err_constexpr_var_non_literal))) { + NewVD->setInvalidDecl(); + return false; + } + if (!Previous.empty()) { MergeVarDecl(NewVD, Previous); return true; diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp index fef9a7dae1..117997ee28 100644 --- a/test/CXX/class/class.static/class.static.data/p3.cpp +++ b/test/CXX/class/class.static/class.static.data/p3.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -struct NonLit { // expected-note {{no constexpr constructors}} +struct NonLit { // expected-note 3{{no constexpr constructors}} NonLit(); }; @@ -30,11 +30,11 @@ struct U { static constexpr int a = 0; static constexpr int b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}} static constexpr NonLit h = NonLit(); // expected-error {{cannot have non-literal type 'const NonLit'}} - static constexpr T c = T(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type}} + static constexpr T c = T(); // expected-error {{cannot have non-literal type}} static const T d; }; -template<typename T> constexpr T U<T>::d = T(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-literal type 'const NonLit'}} +template<typename T> constexpr T U<T>::d = T(); // expected-error {{non-literal type 'const NonLit'}} U<int> u1; U<NonLit> u2; // expected-note {{here}} diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp index 6f13faa2fc..70fa2984fa 100644 --- a/test/CodeGenCXX/const-init-cxx11.cpp +++ b/test/CodeGenCXX/const-init-cxx11.cpp @@ -185,9 +185,93 @@ namespace MemberPtr { extern constexpr void (B2::*b2m)() = (void(B2::*)())&D::m; } +namespace LiteralReference { + struct Lit { + constexpr Lit() : n(5) {} + int n; + }; + // FIXME: This should have static initialization, but we do not implement + // that yet. For now, just check that we don't set the (pointer) value of + // the reference to 5! + // + // CHECK: @_ZN16LiteralReference3litE = global {{.*}} null + const Lit &lit = Lit(); +} + +namespace NonLiteralConstexpr { + constexpr int factorial(int n) { + return n ? factorial(n-1) * n : 1; + } + extern void f(int *p); + + struct NonTrivialDtor { + constexpr NonTrivialDtor() : n(factorial(5)), p(&n) {} + ~NonTrivialDtor() { + f(p); + } + + int n; + int *p; + }; + static_assert(!__is_literal(NonTrivialDtor), ""); + // CHECK: @_ZN19NonLiteralConstexpr3ntdE = global {{.*}} { i32 120, i32* getelementptr + NonTrivialDtor ntd; + + struct VolatileMember { + constexpr VolatileMember() : n(5) {} + volatile int n; + }; + static_assert(!__is_literal(VolatileMember), ""); + // CHECK: @_ZN19NonLiteralConstexpr2vmE = global {{.*}} { i32 5 } + VolatileMember vm; + + struct Both { + constexpr Both() : n(10) {} + ~Both(); + volatile int n; + }; + // CHECK: @_ZN19NonLiteralConstexpr1bE = global {{.*}} { i32 10 } + Both b; + + void StaticVars() { + // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE3ntd = {{.*}} { i32 120, i32* getelementptr {{.*}} + // CHECK: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE3ntd = + static NonTrivialDtor ntd; + // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE2vm = {{.*}} { i32 5 } + // CHECK-NOT: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE2vm = + static VolatileMember vm; + // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE1b = {{.*}} { i32 10 } + // CHECK: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE1b = + static Both b; + } +} + // Constant initialization tests go before this point, // dynamic initialization tests go after. +// We must emit a constant initializer for NonLiteralConstexpr::ntd, but also +// emit an initializer to register its destructor. +// CHECK: define {{.*}}cxx_global_var_init{{.*}} +// CHECK-NOT: NonLiteralConstexpr +// CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr14NonTrivialDtorD1Ev {{.*}} @_ZN19NonLiteralConstexpr3ntdE +// CHECK-NEXT: ret void + +// We don't need to emit any dynamic initialization for NonLiteralConstexpr::vm. +// CHECK-NOT: NonLiteralConstexpr2vm + +// We must emit a constant initializer for NonLiteralConstexpr::b, but also +// emit an initializer to register its destructor. +// CHECK: define {{.*}}cxx_global_var_init{{.*}} +// CHECK-NOT: NonLiteralConstexpr +// CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr4BothD1Ev {{.*}} @_ZN19NonLiteralConstexpr1bE +// CHECK-NEXT: ret void + +// CHECK: define {{.*}}NonLiteralConstexpr10StaticVars +// CHECK-NOT: } +// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr14NonTrivialDtorD1Ev +// CHECK-NOT: } +// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr4BothD1Ev + namespace CrossFuncLabelDiff { // Make sure we refuse to constant-fold the variable b. constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); } |