Deal with a horrible C++11 special case. If a non-literal type has a constexpr

constructor, and that constructor is used to initialize an object of static
storage duration such that all members and bases are initialized by constant
expressions, constant initialization is performed. In this case, the object
can still have a non-trivial destructor, and if it does, we must emit a dynamic
initializer which performs no initialization and instead simply registers that
destructor.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150419 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2012-02-13 22:16:19 +00:00
Родитель 5ad3af90dd
Коммит 7ca4850a3e
13 изменённых файлов: 179 добавлений и 46 удалений

Просмотреть файл

@ -855,7 +855,8 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info, static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E, const LValue &This, const Expr *E,
CheckConstantExpressionKind CCEK CheckConstantExpressionKind CCEK
= CCEK_Constant); = CCEK_Constant,
bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(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, 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. /// which were initialized earlier.
static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info, static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E, const LValue &This, const Expr *E,
CheckConstantExpressionKind CCEK) { CheckConstantExpressionKind CCEK,
if (!CheckLiteralType(Info, E)) bool AllowNonLiteralTypes) {
if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E))
return false; return false;
if (E->isRValue()) { if (E->isRValue()) {
@ -5941,9 +5943,6 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
EvalInfo InitInfo(Ctx, EStatus); EvalInfo InitInfo(Ctx, EStatus);
InitInfo.setEvaluatingDecl(VD, Value); InitInfo.setEvaluatingDecl(VD, Value);
if (!CheckLiteralType(InitInfo, this))
return false;
LValue LVal; LValue LVal;
LVal.set(VD); LVal.set(VD);
@ -5954,11 +5953,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
if (Ctx.getLangOptions().CPlusPlus && !VD->hasLocalStorage() && if (Ctx.getLangOptions().CPlusPlus && !VD->hasLocalStorage() &&
!VD->getType()->isReferenceType()) { !VD->getType()->isReferenceType()) {
ImplicitValueInitExpr VIE(VD->getType()); ImplicitValueInitExpr VIE(VD->getType());
if (!EvaluateConstantExpression(Value, InitInfo, LVal, &VIE)) if (!EvaluateConstantExpression(Value, InitInfo, LVal, &VIE, CCEK_Constant,
/*AllowNonLiteralTypes=*/true))
return false; return false;
} }
return EvaluateConstantExpression(Value, InitInfo, LVal, this) && return EvaluateConstantExpression(Value, InitInfo, LVal, this, CCEK_Constant,
/*AllowNonLiteralTypes=*/true) &&
!EStatus.HasSideEffects; !EStatus.HasSideEffects;
} }

Просмотреть файл

@ -168,6 +168,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
const VarDecl &D, const VarDecl &D,
llvm::GlobalVariable *GV) { llvm::GlobalVariable *GV,
bool PerformInit) {
ErrorUnsupportedABI(CGF, "static local variable initialization"); ErrorUnsupportedABI(CGF, "static local variable initialization");
} }

Просмотреть файл

@ -226,12 +226,14 @@ public:
/// Emits the guarded initializer and destructor setup for the given /// Emits the guarded initializer and destructor setup for the given
/// variable, given that it couldn't be emitted as a constant. /// 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: /// The variable may be:
/// - a static local variable /// - a static local variable
/// - a static data member of a class template instantiation /// - a static data member of a class template instantiation
virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr); llvm::GlobalVariable *DeclPtr, bool PerformInit);
}; };

Просмотреть файл

@ -196,6 +196,14 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
return GV; 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 /// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the
/// global variable that has already been created for it. If the initializer /// 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 /// 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. // be constant.
GV->setConstant(false); GV->setConstant(false);
EmitCXXGuardedInit(D, GV); EmitCXXGuardedInit(D, GV, /*PerformInit*/true);
} }
return GV; return GV;
} }
@ -248,6 +256,16 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
} }
GV->setInitializer(Init); 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; return GV;
} }

Просмотреть файл

@ -102,17 +102,21 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
} }
void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
llvm::Constant *DeclPtr) { llvm::Constant *DeclPtr,
bool PerformInit) {
const Expr *Init = D.getInit(); const Expr *Init = D.getInit();
QualType T = D.getType(); QualType T = D.getType();
if (!T->isReferenceType()) { if (!T->isReferenceType()) {
EmitDeclInit(*this, D, DeclPtr); if (PerformInit)
EmitDeclInit(*this, D, DeclPtr);
EmitDeclDestroy(*this, D, DeclPtr); EmitDeclDestroy(*this, D, DeclPtr);
return; return;
} }
assert(PerformInit && "cannot have constant initializer which needs "
"destruction for reference");
unsigned Alignment = getContext().getDeclAlign(&D).getQuantity(); unsigned Alignment = getContext().getDeclAlign(&D).getQuantity();
RValue RV = EmitReferenceBindingToExpr(Init, &D); RValue RV = EmitReferenceBindingToExpr(Init, &D);
EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T); EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T);
@ -152,7 +156,8 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
} }
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, 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. // 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 // This diagnostic is hard-coded for Darwin's use case; we can find
// better phrasing if someone else needs it. // better phrasing if someone else needs it.
@ -161,7 +166,7 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
"this initialization requires a guard variable, which " "this initialization requires a guard variable, which "
"the kernel does not support"); "the kernel does not support");
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr); CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
} }
static llvm::Function * static llvm::Function *
@ -186,14 +191,16 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
void void
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr) { llvm::GlobalVariable *Addr,
bool PerformInit) {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
// Create a variable initialization function. // Create a variable initialization function.
llvm::Function *Fn = llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init"); CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init");
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr); CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
PerformInit);
if (D->hasAttr<InitPriorityAttr>()) { if (D->hasAttr<InitPriorityAttr>()) {
unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority(); unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority();
@ -267,7 +274,8 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() {
/// Emit the code necessary to initialize the given global variable. /// Emit the code necessary to initialize the given global variable.
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D, const VarDecl *D,
llvm::GlobalVariable *Addr) { llvm::GlobalVariable *Addr,
bool PerformInit) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().getNullaryFunctionInfo(), getTypes().getNullaryFunctionInfo(),
FunctionArgList(), SourceLocation()); FunctionArgList(), SourceLocation());
@ -277,9 +285,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
// definitions explicitly marked weak. // definitions explicitly marked weak.
if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage || if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage ||
Addr->getLinkage() == llvm::GlobalValue::WeakAnyLinkage) { Addr->getLinkage() == llvm::GlobalValue::WeakAnyLinkage) {
EmitCXXGuardedInit(*D, Addr); EmitCXXGuardedInit(*D, Addr, PerformInit);
} else { } else {
EmitCXXGlobalVarDeclInit(*D, Addr); EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
} }
FinishFunction(); FinishFunction();
@ -357,4 +365,3 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
return fn; return fn;
} }

Просмотреть файл

@ -939,6 +939,15 @@ llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
if (const APValue *Value = D.evaluateValue()) if (const APValue *Value = D.evaluateValue())
return EmitConstantValue(*Value, D.getType(), CGF); 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(); const Expr *E = D.getInit();
assert(E && "No initializer to emit"); assert(E && "No initializer to emit");

Просмотреть файл

@ -2361,7 +2361,8 @@ public:
/// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
/// variable with global storage. /// 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 /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr
/// with the C++ runtime so that its destructor will be called at exit. /// 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 /// possible to prove that an initialization will be done exactly
/// once, e.g. with a static local variable or a static data member /// once, e.g. with a static local variable or a static data member
/// of a class template. /// 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 /// GenerateCXXGlobalInitFunc - Generates code for initializing global
/// variables. /// variables.
@ -2389,7 +2391,8 @@ public:
void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D, const VarDecl *D,
llvm::GlobalVariable *Addr); llvm::GlobalVariable *Addr,
bool PerformInit);
void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest);

Просмотреть файл

@ -1359,7 +1359,9 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = 0; llvm::Constant *Init = 0;
QualType ASTTy = D->getType(); QualType ASTTy = D->getType();
bool NonConstInit = false; CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
bool NeedsGlobalCtor = false;
bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor();
const VarDecl *InitDecl; const VarDecl *InitDecl;
const Expr *InitExpr = D->getAnyInitializer(InitDecl); const Expr *InitExpr = D->getAnyInitializer(InitDecl);
@ -1385,15 +1387,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (getLangOptions().CPlusPlus) { if (getLangOptions().CPlusPlus) {
Init = EmitNullConstant(T); Init = EmitNullConstant(T);
NonConstInit = true; NeedsGlobalCtor = true;
} else { } else {
ErrorUnsupported(D, "static initializer"); ErrorUnsupported(D, "static initializer");
Init = llvm::UndefValue::get(getTypes().ConvertType(T)); Init = llvm::UndefValue::get(getTypes().ConvertType(T));
} }
} else { } else {
// We don't need an initializer, so remove the entry for the delayed // We don't need an initializer, so remove the entry for the delayed
// initializer position (just in case this entry was delayed). // initializer position (just in case this entry was delayed) if we
if (getLangOptions().CPlusPlus) // also don't need to register a destructor.
if (getLangOptions().CPlusPlus && !NeedsGlobalDtor)
DelayedCXXInitPosition.erase(D); 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. // If it is safe to mark the global 'constant', do so now.
GV->setConstant(false); GV->setConstant(false);
if (!NonConstInit && DeclIsConstantGlobal(Context, D, true)) if (!NeedsGlobalCtor && !NeedsGlobalDtor &&
DeclIsConstantGlobal(Context, D, true))
GV->setConstant(true); GV->setConstant(true);
GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
@ -1464,8 +1468,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
SetCommonAttributes(D, GV); SetCommonAttributes(D, GV);
// Emit the initializer function if necessary. // Emit the initializer function if necessary.
if (NonConstInit) if (NeedsGlobalCtor || NeedsGlobalDtor)
EmitCXXGlobalVarDeclInitFunc(D, GV); EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
// Emit global variable debug information. // Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo()) if (CGDebugInfo *DI = getModuleDebugInfo())

Просмотреть файл

@ -900,8 +900,11 @@ private:
/// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals. /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals.
void EmitCXXGlobalDtorFunc(); void EmitCXXGlobalDtorFunc();
/// EmitCXXGlobalVarDeclInitFunc - Emit the function that initializes the
/// specified global (if PerformInit is true) and registers its destructor.
void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
llvm::GlobalVariable *Addr); llvm::GlobalVariable *Addr,
bool PerformInit);
// FIXME: Hardcoding priority here is gross. // FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535); void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);

Просмотреть файл

@ -121,7 +121,7 @@ public:
llvm::Value *&AllocPtr, CharUnits &CookieSize); llvm::Value *&AllocPtr, CharUnits &CookieSize);
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr); llvm::GlobalVariable *DeclPtr, bool PerformInit);
}; };
class ARMCXXABI : public ItaniumCXXABI { class ARMCXXABI : public ItaniumCXXABI {
@ -1016,7 +1016,8 @@ namespace {
/// just special-case it at particular places. /// just special-case it at particular places.
void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
const VarDecl &D, const VarDecl &D,
llvm::GlobalVariable *GV) { llvm::GlobalVariable *GV,
bool PerformInit) {
CGBuilderTy &Builder = CGF.Builder; CGBuilderTy &Builder = CGF.Builder;
// We only need to use thread-safe statics for local variables; // 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. // Emit the initializer and add a global destructor if appropriate.
CGF.EmitCXXGlobalVarDeclInit(D, GV); CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
if (threadsafe) { if (threadsafe) {
// Pop the guard-abort cleanup if we pushed one. // Pop the guard-abort cleanup if we pushed one.

Просмотреть файл

@ -3991,15 +3991,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateParamLists.release()); TemplateParamLists.release());
} }
if (D.getDeclSpec().isConstexprSpecified()) { if (D.getDeclSpec().isConstexprSpecified())
NewVD->setConstexpr(true); 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 // Set the lexical context. If the declarator has a C++ scope specifier, the
@ -4347,6 +4340,13 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
return false; 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()) { if (!Previous.empty()) {
MergeVarDecl(NewVD, Previous); MergeVarDecl(NewVD, Previous);
return true; return true;

Просмотреть файл

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // 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(); NonLit();
}; };
@ -30,11 +30,11 @@ struct U {
static constexpr int a = 0; static constexpr int a = 0;
static constexpr int b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}} 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 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; 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<int> u1;
U<NonLit> u2; // expected-note {{here}} U<NonLit> u2; // expected-note {{here}}

Просмотреть файл

@ -185,9 +185,93 @@ namespace MemberPtr {
extern constexpr void (B2::*b2m)() = (void(B2::*)())&D::m; 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, // Constant initialization tests go before this point,
// dynamic initialization tests go after. // 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 { namespace CrossFuncLabelDiff {
// Make sure we refuse to constant-fold the variable b. // Make sure we refuse to constant-fold the variable b.
constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); } constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); }