Update constexpr implementation to match CWG's chosen approach for core issues

1358, 1360, 1452 and 1453.
 - Instantiations of constexpr functions are always constexpr. This removes the
   need for separate declaration/definition checking, which is now gone.
 - This makes it possible for a constexpr function to be virtual, if they are
   only dependently virtual. Virtual calls to such functions are not constant
   expressions.
 - Likewise, it's now possible for a literal type to have virtual base classes.
   A constexpr constructor for such a type cannot actually produce a constant
   expression, though, so add a special-case diagnostic for a constructor call
   to such a type rather than trying to evaluate it.
 - Classes with trivial default constructors (for which value initialization can
   produce a fully-initialized value) are considered literal types.
 - Classes with volatile members are not literal types.
 - constexpr constructors can be members of non-literal types. We do not yet use
   static initialization for global objects constructed in this way.

llvm-svn: 150359
This commit is contained in:
Richard Smith 2012-02-13 03:54:03 +00:00
parent 779579b332
commit 3607ffee5c
21 changed files with 212 additions and 279 deletions

View File

@ -469,7 +469,8 @@ class CXXRecordDecl : public RecordDecl {
bool HasTrivialDestructor : 1;
/// HasNonLiteralTypeFieldsOrBases - True when this class contains at least
/// one non-static data member or base class of non literal type.
/// one non-static data member or base class of non-literal or volatile
/// type.
bool HasNonLiteralTypeFieldsOrBases : 1;
/// ComputedVisibleConversions - True when visible conversion functions are
@ -1095,8 +1096,8 @@ public:
// (C++ [class.dtor]p3)
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
// hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal type
// non-static data member or base class.
// hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or
// volatile type non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {
return data().HasNonLiteralTypeFieldsOrBases;
}
@ -1116,20 +1117,23 @@ public:
// isLiteral - Whether this class is a literal type.
//
// C++0x [basic.types]p10
// C++11 [basic.types]p10
// A class type that has all the following properties:
// -- a trivial destructor
// -- it has a trivial destructor
// -- every constructor call and full-expression in the
// brace-or-equal-intializers for non-static data members (if any) is
// a constant expression.
// -- it is an aggregate type or has at least one constexpr constructor or
// constructor template that is not a copy or move constructor, and
// -- all non-static data members and base classes of literal types
// -- all of its non-static data members and base classes are of literal
// types
//
// We resolve DR1361 by ignoring the second bullet.
// We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by
// treating types with trivial default constructors as literal types.
bool isLiteral() const {
return hasTrivialDestructor() &&
(isAggregate() || hasConstexprNonCopyMoveConstructor()) &&
(isAggregate() || hasConstexprNonCopyMoveConstructor() ||
hasTrivialDefaultConstructor()) &&
!hasNonLiteralTypeFieldsOrBases();
}

View File

@ -28,6 +28,11 @@ def note_constexpr_lshift_discards : Note<"signed left shift discards bits">;
def note_constexpr_invalid_function : Note<
"%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
"be used in a constant expression">;
def note_constexpr_virtual_call : Note<
"cannot evaluate virtual function call in a constant expression">;
def note_constexpr_virtual_base : Note<
"cannot construct object of type %0 with virtual base class "
"in a constant expression">;
def note_constexpr_nonliteral : Note<
"non-literal type %0 cannot be used in a constant expression">;
def note_constexpr_non_global : Note<

View File

@ -1361,6 +1361,8 @@ def err_invalid_constexpr_var_decl : Error<
"constexpr variable declaration must be a definition">;
def err_constexpr_static_mem_var_requires_init : Error<
"declaration of constexpr static data member %0 requires an initializer">;
def err_constexpr_var_non_literal : Error<
"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_redecl_mismatch : Error<
@ -1369,29 +1371,17 @@ def err_constexpr_redecl_mismatch : Error<
def note_constexpr_redecl_mismatch : Note<
"previous declaration was %select{not |}0marked constexpr">;
def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
def note_constexpr_tmpl_virtual : Note<"function template instantiation is not "
"constexpr because it is virtual">;
def err_constexpr_virtual_base : Error<
"constexpr %select{member function|constructor}0 not allowed in "
"%select{class|struct}1 with virtual base %plural{1:class|:classes}2">;
def note_constexpr_tmpl_virtual_base : Note<
"%select{function|constructor}0 template instantiation is "
"not constexpr because %select{class|struct}1 has virtual base "
"%plural{1:class|:classes}2">;
def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual "
"base %plural{1:class|:classes}1 is not a literal type">;
def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
def err_constexpr_non_literal_return : Error<
"constexpr function's return type %0 is not a literal type">;
def note_constexpr_tmpl_non_literal_return : Note<
"function template instantiation is not constexpr because return type %0 is "
"not a literal type">;
def err_constexpr_non_literal_param : Error<
"constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is "
"not a literal type">;
def note_constexpr_tmpl_non_literal_param : Note<
"%select{function|constructor}1 template instantiation is not constexpr "
"because %ordinal0 parameter type %2 is not a literal type">;
def err_constexpr_body_invalid_stmt : Error<
"statement not allowed in constexpr %select{function|constructor}0">;
def err_constexpr_type_definition : Error<
@ -1426,7 +1416,8 @@ def note_non_literal_no_constexpr_ctors : Note<
def note_non_literal_base_class : Note<
"%0 is not literal because it has base class %1 of non-literal type">;
def note_non_literal_field : Note<
"%0 is not literal because it has data member %1 of non-literal type %2">;
"%0 is not literal because it has data member %1 of "
"%select{non-literal|volatile}3 type %2">;
def note_non_literal_user_provided_dtor : Note<
"%0 is not literal because it has a user-provided destructor">;
def note_non_literal_nontrivial_dtor : Note<

View File

@ -835,8 +835,7 @@ public:
PartialDiagnostic> Note);
bool RequireLiteralType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
bool AllowIncompleteType = false);
const PartialDiagnostic &PD);
QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
const CXXScopeSpec &SS, QualType T);
@ -1004,23 +1003,8 @@ public:
bool &AddToScope);
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
/// \brief The kind of constexpr declaration checking we are performing.
///
/// The kind affects which diagnostics (if any) are emitted if the function
/// does not satisfy the requirements of a constexpr function declaration.
enum CheckConstexprKind {
/// \brief Check a constexpr function declaration, and produce errors if it
/// does not satisfy the requirements.
CCK_Declaration,
/// \brief Check a constexpr function template instantiation.
CCK_Instantiation,
/// \brief Produce notes explaining why an instantiation was not constexpr.
CCK_NoteNonConstexprInstantiation
};
bool CheckConstexprFunctionDecl(const FunctionDecl *FD,
CheckConstexprKind CCK);
bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body,
bool IsInstantiation);
bool CheckConstexprFunctionDecl(const FunctionDecl *FD);
bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
// Returns true if the function declaration is a redeclaration

View File

@ -799,8 +799,8 @@ NotASpecialMember:;
data().IsStandardLayout = false;
}
// Record if this field is the first non-literal field or base.
if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
// Record if this field is the first non-literal or volatile field or base.
if (!T->isLiteralType() || T.isVolatileQualified())
data().HasNonLiteralTypeFieldsOrBases = true;
if (Field->hasInClassInitializer()) {

View File

@ -2033,6 +2033,12 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
if (!Info.CheckCallLimit(CallLoc))
return false;
const CXXRecordDecl *RD = Definition->getParent();
if (RD->getNumVBases()) {
Info.Diag(CallLoc, diag::note_constexpr_virtual_base) << RD;
return false;
}
CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues.data());
// If it's a delegating constructor, just delegate.
@ -2044,7 +2050,6 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
// For a trivial copy or move constructor, perform an APValue copy. This is
// essential for unions, where the operations performed by the constructor
// cannot be represented by ctor-initializers.
const CXXRecordDecl *RD = Definition->getParent();
if (Definition->isDefaulted() &&
((Definition->isCopyConstructor() && RD->hasTrivialCopyConstructor()) ||
(Definition->isMoveConstructor() && RD->hasTrivialMoveConstructor()))) {
@ -2083,7 +2088,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
QualType BaseType((*I)->getBaseClass(), 0);
#ifndef NDEBUG
// Non-virtual base classes are initialized in the order in the class
// definition. We cannot have a virtual base class for a literal type.
// definition. We have already checked for virtual base classes.
assert(!BaseIt->isVirtual() && "virtual base for literal type");
assert(Info.Ctx.hasSameType(BaseIt->getType(), BaseType) &&
"base class initializers not in expected order");
@ -2414,6 +2419,7 @@ public:
const FunctionDecl *FD = 0;
LValue *This = 0, ThisVal;
llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
@ -2424,6 +2430,7 @@ public:
return false;
Member = ME->getMemberDecl();
This = &ThisVal;
HasQualifier = ME->hasQualifier();
} else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
// Indirect bound member calls ('.*' or '->*').
Member = HandleMemberPointerAccess(Info, BE, ThisVal, false);
@ -2472,6 +2479,12 @@ public:
if (This && !This->checkSubobject(Info, E, CSK_This))
return false;
// DR1358 allows virtual constexpr functions in some cases. Don't allow
// calls to such functions in constant expressions.
if (This && !HasQualifier &&
isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isVirtual())
return Error(E, diag::note_constexpr_virtual_call);
const FunctionDecl *Definition = 0;
Stmt *Body = FD->getBody(Definition);
APValue Result;

View File

@ -3991,8 +3991,15 @@ 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
@ -5347,10 +5354,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() &&
!CheckConstexprFunctionDecl(NewFD, CCK_Declaration))
NewFD->setInvalidDecl();
NamedDecl *PrincipalDecl = (FunctionTemplate
? cast<NamedDecl>(FunctionTemplate)
: NewFD);
@ -6223,8 +6226,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (DclT->isDependentType()) {
// Allow any 'static constexpr' members, whether or not they are of literal
// type. We separately check that the initializer is a constant expression,
// which implicitly requires the member to be of literal type.
// type. We separately check that every constexpr variable is of literal
// type.
} else if (VDecl->isConstexpr()) {
// Require constness.
@ -7350,8 +7353,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
ActivePolicy = &WP;
}
if (FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
!CheckConstexprFunctionBody(FD, Body, IsInstantiation))
if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
(!CheckConstexprFunctionDecl(FD) ||
!CheckConstexprFunctionBody(FD, Body)))
FD->setInvalidDecl();
assert(ExprCleanupObjects.empty() && "Leftover temporaries in function");

View File

@ -632,9 +632,9 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
// CheckConstexprParameterTypes - Check whether a function's parameter types
// are all literal types. If so, return true. If not, produce a suitable
// diagnostic depending on @p CCK and return false.
static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD,
Sema::CheckConstexprKind CCK) {
// diagnostic and return false.
static bool CheckConstexprParameterTypes(Sema &SemaRef,
const FunctionDecl *FD) {
unsigned ArgIndex = 0;
const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
for (FunctionProtoType::arg_type_iterator i = FT->arg_type_begin(),
@ -642,63 +642,37 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD,
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
SourceLocation ParamLoc = PD->getLocation();
if (!(*i)->isDependentType() &&
SemaRef.RequireLiteralType(ParamLoc, *i, CCK == Sema::CCK_Declaration ?
SemaRef.RequireLiteralType(ParamLoc, *i,
SemaRef.PDiag(diag::err_constexpr_non_literal_param)
<< ArgIndex+1 << PD->getSourceRange()
<< isa<CXXConstructorDecl>(FD) :
SemaRef.PDiag(),
/*AllowIncompleteType*/ true)) {
if (CCK == Sema::CCK_NoteNonConstexprInstantiation)
SemaRef.Diag(ParamLoc, diag::note_constexpr_tmpl_non_literal_param)
<< ArgIndex+1 << PD->getSourceRange()
<< isa<CXXConstructorDecl>(FD) << *i;
<< isa<CXXConstructorDecl>(FD)))
return false;
}
}
return true;
}
// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
// the requirements of a constexpr function declaration or a constexpr
// constructor declaration. Return true if it does, false if not.
// the requirements of a constexpr function definition or a constexpr
// constructor definition. If so, return true. If not, produce appropriate
// diagnostics and return false.
//
// This implements C++11 [dcl.constexpr]p3,4, as amended by N3308.
//
// \param CCK Specifies whether to produce diagnostics if the function does not
// satisfy the requirements.
bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD,
CheckConstexprKind CCK) {
assert((CCK != CCK_NoteNonConstexprInstantiation ||
(NewFD->getTemplateInstantiationPattern() &&
NewFD->getTemplateInstantiationPattern()->isConstexpr())) &&
"only constexpr templates can be instantiated non-constexpr");
// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
if (MD && MD->isInstance()) {
// C++11 [dcl.constexpr]p4: In the definition of a constexpr constructor...
// In addition, either its function-body shall be = delete or = default or
// it shall satisfy the following constraints:
// C++11 [dcl.constexpr]p4:
// The definition of a constexpr constructor shall satisfy the following
// constraints:
// - the class shall not have any virtual base classes;
//
// We apply this to constexpr member functions too: the class cannot be a
// literal type, so the members are not permitted to be constexpr.
const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
// Note, this is still illegal if the body is = default, since the
// implicit body does not satisfy the requirements of a constexpr
// constructor. We also reject cases where the body is = delete, as
// required by N3308.
if (CCK != CCK_Instantiation) {
Diag(NewFD->getLocation(),
CCK == CCK_Declaration ? diag::err_constexpr_virtual_base
: diag::note_constexpr_tmpl_virtual_base)
<< isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
<< RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
Diag(I->getSourceRange().getBegin(),
diag::note_constexpr_virtual_base_here) << I->getSourceRange();
}
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
<< isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
<< RD->getNumVBases();
for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
E = RD->vbases_end(); I != E; ++I)
Diag(I->getSourceRange().getBegin(),
diag::note_constexpr_virtual_base_here) << I->getSourceRange();
return false;
}
}
@ -710,39 +684,29 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD,
// - it shall not be virtual;
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
if (Method && Method->isVirtual()) {
if (CCK != CCK_Instantiation) {
Diag(NewFD->getLocation(),
CCK == CCK_Declaration ? diag::err_constexpr_virtual
: diag::note_constexpr_tmpl_virtual);
Diag(NewFD->getLocation(), diag::err_constexpr_virtual);
// If it's not obvious why this function is virtual, find an overridden
// function which uses the 'virtual' keyword.
const CXXMethodDecl *WrittenVirtual = Method;
while (!WrittenVirtual->isVirtualAsWritten())
WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
if (WrittenVirtual != Method)
Diag(WrittenVirtual->getLocation(),
diag::note_overridden_virtual_function);
}
// If it's not obvious why this function is virtual, find an overridden
// function which uses the 'virtual' keyword.
const CXXMethodDecl *WrittenVirtual = Method;
while (!WrittenVirtual->isVirtualAsWritten())
WrittenVirtual = *WrittenVirtual->begin_overridden_methods();
if (WrittenVirtual != Method)
Diag(WrittenVirtual->getLocation(),
diag::note_overridden_virtual_function);
return false;
}
// - its return type shall be a literal type;
QualType RT = NewFD->getResultType();
if (!RT->isDependentType() &&
RequireLiteralType(NewFD->getLocation(), RT, CCK == CCK_Declaration ?
PDiag(diag::err_constexpr_non_literal_return) :
PDiag(),
/*AllowIncompleteType*/ true)) {
if (CCK == CCK_NoteNonConstexprInstantiation)
Diag(NewFD->getLocation(),
diag::note_constexpr_tmpl_non_literal_return) << RT;
RequireLiteralType(NewFD->getLocation(), RT,
PDiag(diag::err_constexpr_non_literal_return)))
return false;
}
}
// - each of its parameter types shall be a literal type;
if (!CheckConstexprParameterTypes(*this, NewFD, CCK))
if (!CheckConstexprParameterTypes(*this, NewFD))
return false;
return true;
@ -854,8 +818,7 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
///
/// \return true if the body is OK, false if we have diagnosed a problem.
bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body,
bool IsInstantiation) {
bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
if (isa<CXXTryStmt>(Body)) {
// C++11 [dcl.constexpr]p3:
// The definition of a constexpr function shall satisfy the following
@ -1005,7 +968,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body,
// - every constructor involved in initializing non-static data members and
// base class sub-objects shall be a constexpr constructor.
llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
if (!IsInstantiation && !Expr::isPotentialConstantExpr(Dcl, Diags)) {
if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr)
<< isa<CXXConstructorDecl>(Dcl);
for (size_t I = 0, N = Diags.size(); I != N; ++I)
@ -3755,9 +3718,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// const. [...] The class of which that function is a member shall be
// a literal type.
//
// It's fine to diagnose constructors here too: such constructors cannot
// produce a constant expression, so are ill-formed (no diagnostic required).
//
// If the class has virtual bases, any constexpr members will already have
// been diagnosed by the checks performed on the member declaration, so
// suppress this (less useful) diagnostic.
@ -3766,16 +3726,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
if (M->isConstexpr() && M->isInstance()) {
if (M->isConstexpr() && M->isInstance() && !isa<CXXConstructorDecl>(*M)) {
switch (Record->getTemplateSpecializationKind()) {
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
// If a template instantiates to a non-literal type, but its members
// instantiate to constexpr functions, the template is technically
// ill-formed, but we allow it for sanity. Such members are treated as
// non-constexpr.
(*M)->setConstexpr(false);
// ill-formed, but we allow it for sanity.
continue;
case TSK_Undeclared:

View File

@ -1034,7 +1034,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->getLocation(), D->getDeclName(), T, TInfo,
D->getStorageClass(), D->getStorageClassAsWritten(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
/*isConstexpr*/ false);
D->isConstexpr());
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
@ -1379,7 +1379,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
false, /*isConstexpr*/ false);
false, Constructor->isConstexpr());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
@ -1390,7 +1390,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(),
Conversion->isExplicit(),
/*isConstexpr*/ false,
Conversion->isConstexpr(),
Conversion->getLocEnd());
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record,
@ -1398,7 +1398,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
D->isStatic(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
/*isConstexpr*/ false, D->getLocEnd());
D->isConstexpr(), D->getLocEnd());
}
if (QualifierLoc)
@ -2305,13 +2305,6 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI));
}
// C++0x [dcl.constexpr]p6: If the instantiated template specialization of
// a constexpr function template satisfies the requirements for a constexpr
// function, then it is a constexpr function.
if (Tmpl->isConstexpr() &&
SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation))
New->setConstexpr(true);
const FunctionDecl* Definition = Tmpl;
// Get the definition. Leaves the variable unchanged if undefined.

View File

@ -4243,19 +4243,14 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
/// @param PD The partial diagnostic that will be printed out if T is not a
/// literal type.
///
/// @param AllowIncompleteType If true, an incomplete type will be considered
/// acceptable.
///
/// @returns @c true if @p T is not a literal type and a diagnostic was emitted,
/// @c false otherwise.
bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
bool AllowIncompleteType) {
const PartialDiagnostic &PD) {
assert(!T->isDependentType() && "type should not be dependent");
bool Incomplete = RequireCompleteType(Loc, T, 0);
if (T->isLiteralType() ||
(AllowIncompleteType && Incomplete && !T->isVoidType()))
RequireCompleteType(Loc, T, 0);
if (T->isLiteralType())
return false;
if (PD.getDiagID() == 0)
@ -4273,8 +4268,9 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
// If the class has virtual base classes, then it's not an aggregate, and
// cannot have any constexpr constructors, so is non-literal. This is better
// to diagnose than the resulting absence of constexpr constructors.
// cannot have any constexpr constructors or a trivial default constructor,
// so is non-literal. This is better to diagnose than the resulting absence
// of constexpr constructors.
if (RD->getNumVBases()) {
Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
<< RD->isStruct() << RD->getNumVBases();
@ -4282,29 +4278,9 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
E = RD->vbases_end(); I != E; ++I)
Diag(I->getSourceRange().getBegin(),
diag::note_constexpr_virtual_base_here) << I->getSourceRange();
} else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor()) {
} else if (!RD->isAggregate() && !RD->hasConstexprNonCopyMoveConstructor() &&
!RD->hasTrivialDefaultConstructor()) {
Diag(RD->getLocation(), diag::note_non_literal_no_constexpr_ctors) << RD;
switch (RD->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
break;
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
// If the base template had constexpr constructors which were
// instantiated as non-constexpr constructors, explain why.
for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
E = RD->ctor_end(); I != E; ++I) {
if ((*I)->isCopyConstructor() || (*I)->isMoveConstructor())
continue;
FunctionDecl *Base = (*I)->getInstantiatedFromMemberFunction();
if (Base && Base->isConstexpr())
CheckConstexprFunctionDecl(*I, CCK_NoteNonConstexprInstantiation);
}
}
} else if (RD->hasNonLiteralTypeFieldsOrBases()) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
@ -4317,9 +4293,11 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
}
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I) {
if (!(*I)->getType()->isLiteralType()) {
if (!(*I)->getType()->isLiteralType() ||
(*I)->getType().isVolatileQualified()) {
Diag((*I)->getLocation(), diag::note_non_literal_field)
<< RD << (*I) << (*I)->getType();
<< RD << (*I) << (*I)->getType()
<< (*I)->getType().isVolatileQualified();
return true;
}
}

View File

@ -5,22 +5,23 @@ struct NonLiteral { NonLiteral(); };
// A type is a literal type if it is:
// - a scalar type
constexpr int f1(double);
constexpr int f1(double) { return 0; }
// - a reference type
struct S { S(); };
constexpr int f2(S &);
constexpr int f2(S &) { return 0; }
// - a class type that has all of the following properties:
// - it has a trivial destructor
struct UserProvDtor {
constexpr UserProvDtor(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
constexpr int f(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
~UserProvDtor(); // expected-note {{has a user-provided destructor}}
};
struct NonTrivDtor {
constexpr NonTrivDtor(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
constexpr NonTrivDtor();
constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
};
struct NonTrivDtorBase {
@ -30,16 +31,16 @@ template<typename T>
struct DerivedFromNonTrivDtor : T { // expected-note {{'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not literal because it has base class 'NonTrivDtorBase' of non-literal type}}
constexpr DerivedFromNonTrivDtor();
};
constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
constexpr int f(DerivedFromNonTrivDtor<NonTrivDtorBase>) { return 0; } // expected-error {{constexpr function's 1st parameter type 'DerivedFromNonTrivDtor<NonTrivDtorBase>' is not a literal type}}
struct TrivDtor {
constexpr TrivDtor();
};
constexpr int f(TrivDtor);
constexpr int f(TrivDtor) { return 0; }
struct TrivDefaultedDtor {
constexpr TrivDefaultedDtor();
~TrivDefaultedDtor() = default;
};
constexpr int f(TrivDefaultedDtor);
constexpr int f(TrivDefaultedDtor) { return 0; }
// - it is an aggregate type or has at least one constexpr constructor or
// constexpr constructor template that is not a copy or move constructor
@ -52,36 +53,41 @@ struct CtorTemplate {
template<typename T> constexpr CtorTemplate(T);
};
struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}}
constexpr CopyCtorOnly(CopyCtorOnly&); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
constexpr CopyCtorOnly(CopyCtorOnly&);
constexpr int f(); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
};
struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}}
constexpr MoveCtorOnly(MoveCtorOnly&&); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
constexpr MoveCtorOnly(MoveCtorOnly&&);
constexpr int f(); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
};
template<typename T>
struct CtorArg { // expected-note {{no constexpr constructors other than copy or move constructors}}
constexpr CtorArg(T); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}}
struct CtorArg {
constexpr CtorArg(T);
};
constexpr int f(CtorArg<int>);
constexpr int f(CtorArg<NonLiteral>); // expected-error {{not a literal type}}
constexpr int f(CtorArg<int>) { return 0; } // ok
constexpr int f(CtorArg<NonLiteral>) { return 0; } // ok, ctor is still constexpr
// We have a special-case diagnostic for classes with virtual base classes.
struct VBase {};
struct HasVBase : virtual VBase {}; // expected-note 2{{virtual base class declared here}}
struct Derived : HasVBase {
constexpr Derived(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
constexpr Derived() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
};
template<typename T> struct DerivedFromVBase : T { // expected-note {{struct with virtual base class is not a literal type}}
constexpr DerivedFromVBase();
};
constexpr int f(DerivedFromVBase<HasVBase>); // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase<HasVBase>' is not a literal type}}
constexpr int f(DerivedFromVBase<HasVBase>) {} // expected-error {{constexpr function's 1st parameter type 'DerivedFromVBase<HasVBase>' is not a literal type}}
template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {}
constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // expected-error {{constant expression}} expected-note {{cannot construct object of type 'DerivedFromVBase<HasVBase>' with virtual base class in a constant expression}}
// - it has all non-static data members and base classes of literal types
struct NonLitMember {
S s; // expected-note {{has data member 's' of non-literal type 'S'}}
};
constexpr int f(NonLitMember); // expected-error {{1st parameter type 'NonLitMember' is not a literal type}}
constexpr int f(NonLitMember) {} // expected-error {{1st parameter type 'NonLitMember' is not a literal type}}
struct NonLitBase :
S { // expected-note {{base class 'S' of non-literal type}}
constexpr NonLitBase(); // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
constexpr NonLitBase();
constexpr int f() { return 0; } // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
};
struct LitMemBase : Agg {
Agg agg;
@ -91,8 +97,8 @@ struct MemberType {
T t; // expected-note {{'MemberType<NonLiteral>' is not literal because it has data member 't' of non-literal type 'NonLiteral'}}
constexpr MemberType();
};
constexpr int f(MemberType<int>);
constexpr int f(MemberType<NonLiteral>); // expected-error {{not a literal type}}
constexpr int f(MemberType<int>) { return 0; }
constexpr int f(MemberType<NonLiteral>) { return 0; } // expected-error {{not a literal type}}
// - an array of literal type
struct ArrGood {
@ -101,9 +107,9 @@ struct ArrGood {
TrivDtor td[3];
TrivDefaultedDtor tdd[3];
};
constexpr int f(ArrGood);
constexpr int f(ArrGood) { return 0; }
struct ArrBad {
S s[3]; // expected-note {{data member 's' of non-literal type 'S [3]'}}
};
constexpr int f(ArrBad); // expected-error {{1st parameter type 'ArrBad' is not a literal type}}
constexpr int f(ArrBad) { return 0; } // expected-error {{1st parameter type 'ArrBad' is not a literal type}}

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct NonLit {
struct NonLit { // expected-note {{no constexpr constructors}}
NonLit();
};
@ -29,15 +29,14 @@ template<typename T>
struct U {
static constexpr int a = 0;
static constexpr int b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}}
// FIXME: It'd be nice to error on this at template definition time.
static constexpr NonLit h = NonLit(); // expected-error 2{{must be initialized by a constant expression}} expected-note 2{{non-literal type}}
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 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'}}
U<int> u1; // expected-note {{here}}
U<int> u1;
U<NonLit> u2; // expected-note {{here}}
static_assert(U<int>::a == 0, "");

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct notlit {
struct notlit { // expected-note {{not literal because}}
notlit() {}
};
struct notlit2 {
@ -20,7 +20,7 @@ constexpr int s1::mi2 = 0;
// not a definition of an object
constexpr extern int i2; // expected-error {{constexpr variable declaration must be a definition}}
// not a literal type
constexpr notlit nl1; // expected-error {{constexpr variable 'nl1' must be initialized by a constant expression}} expected-note {{non-literal type 'const notlit' cannot be used in a constant expression}}
constexpr notlit nl1; // expected-error {{constexpr variable cannot have non-literal type 'const notlit'}}
// function parameters
void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}
// non-static member
@ -77,11 +77,11 @@ struct S {
// explicit specialization can differ in constepxr
// FIXME: When checking the explicit specialization, we implicitly instantiate
// the primary template then claim a constexpr mismatch.
template <> notlit ft(notlit nl) { return nl; }
template <> notlit ft(notlit nl) { return nl; } // unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
template <> char ft(char c) { return c; } // desired-note {{previous}} unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
template <> constexpr char ft(char nl); // desired-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
template <> constexpr int gt(int nl) { return nl; } // unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
template <> notlit S::f() const { return notlit(); }
template <> notlit S::f() const { return notlit(); } // unexpected-error {{follows constexpr declaration}} unexpected-note {{here}}
template <> constexpr int S::g() { return 0; } // desired-note {{previous}} unexpected-error {{follows non-constexpr declaration}} unexpected-note {{here}}
template <> int S::g() const; // desired-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
// specializations can drop the 'constexpr' but not the implied 'const'.

View File

@ -8,7 +8,7 @@ namespace M {
typedef double D;
}
struct NonLiteral { // expected-note 4{{no constexpr constructors}}
struct NonLiteral { // expected-note 2{{no constexpr constructors}}
NonLiteral() {}
NonLiteral(int) {}
};
@ -24,31 +24,28 @@ struct SS : S {
int ImplicitlyVirtual() const;
};
// Note, the wording applies constraints to the definition of constexpr
// functions, but we intentionally apply all that we can to the declaration
// instead. See DR1360.
// The definition of a constexpr function shall satisfy the following
// constraints:
struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}}
constexpr T(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
constexpr T();
constexpr int f(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
// - it shall not be virtual;
virtual constexpr int ExplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
virtual constexpr int ExplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
constexpr int ImplicitlyVirtual(); // expected-error {{virtual function cannot be constexpr}}
constexpr int ImplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
// - its return type shall be a literal type;
constexpr NonLiteral NonLiteralReturn(); // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
constexpr void VoidReturn(); // expected-error {{constexpr function's return type 'void' is not a literal type}}
constexpr NonLiteral NonLiteralReturn() { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
constexpr void VoidReturn() { return; } // expected-error {{constexpr function's return type 'void' is not a literal type}}
constexpr ~T(); // expected-error {{destructor cannot be marked constexpr}}
typedef NonLiteral F();
constexpr F NonLiteralReturn2; // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
constexpr F NonLiteralReturn2; // ok until definition
// - each of its parameter types shall be a literal type;
constexpr int NonLiteralParam(NonLiteral); // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
constexpr int NonLiteralParam(NonLiteral) { return 0; } // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
typedef int G(NonLiteral);
constexpr G NonLiteralParam2; // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
constexpr G NonLiteralParam2; // ok until definition
// - its function-body shall be = delete, = default,
constexpr int Deleted() = delete;
@ -65,7 +62,7 @@ struct U {
};
struct V : virtual U { // expected-note {{here}}
constexpr int F(); // expected-error {{constexpr member function not allowed in struct with virtual base class}}
constexpr int F() { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}}
};
// or a compound-statememt that contains only

View File

@ -18,16 +18,12 @@ struct Literal {
operator int() const { return 0; }
};
// Note, the wording applies constraints to the definition of constexpr
// constructors, but we intentionally apply all that we can to the declaration
// instead. See DR1360.
// In the definition of a constexpr constructor, each of the parameter types
// shall be a literal type.
struct S {
constexpr S(int, N::C);
constexpr S(int, NonLiteral, N::C); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
constexpr S(int, NonLiteral = 42); // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
constexpr S(int, N::C) {}
constexpr S(int, NonLiteral, N::C) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
constexpr S(int, NonLiteral = 42) {} // expected-error {{constexpr constructor's 2nd parameter type 'NonLiteral' is not a literal type}}
// In addition, either its function-body shall be = delete or = default
constexpr S() = default;
@ -38,14 +34,14 @@ struct S {
// - the class shall not have any virtual base classes;
struct T : virtual S { // expected-note {{here}}
constexpr T(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
constexpr T() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
};
namespace IndirectVBase {
struct A {};
struct B : virtual A {}; // expected-note {{here}}
class C : public B {
public:
constexpr C(); // expected-error {{constexpr constructor not allowed in class with virtual base class}}
constexpr C() {} // expected-error {{constexpr constructor not allowed in class with virtual base class}}
};
}

View File

@ -10,7 +10,7 @@ namespace M {
struct NonLiteral {
NonLiteral() {}
NonLiteral(int) {}
NonLiteral(int) {} // expected-note 2{{here}}
operator int() const { return 0; }
};
struct Literal {
@ -19,7 +19,7 @@ struct Literal {
};
struct S {
virtual int ImplicitlyVirtual();
virtual int ImplicitlyVirtual() const;
};
struct T {};
@ -27,48 +27,42 @@ template<typename T> struct ImplicitVirtualFromDependentBase : T {
constexpr int ImplicitlyVirtual() { return 0; }
};
// FIXME: Can't test this until we have function invocation substitution
#if 0
constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // desired-error {{not a constant expression}}
constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}}
constexpr int b = ImplicitVirtualFromDependentBase<T>().ImplicitlyVirtual(); // ok
#endif
constexpr int c = ImplicitVirtualFromDependentBase<S>().ImplicitVirtualFromDependentBase<S>::ImplicitlyVirtual();
template<typename R> struct ConstexprMember {
constexpr R F() { return 0; }
};
// FIXME: Can't test this until we have function invocation substitution
#if 0
constexpr int c = ConstexprMember<int>().F(); // ok
constexpr int d = ConstexprMember<NonLiteral>().F(); // desired-error {{not a constant expression}}
#endif
constexpr int d = ConstexprMember<int>().F(); // ok
constexpr int e = ConstexprMember<NonLiteral>().F(); // expected-error {{constant expression}}
template<typename ...P> struct ConstexprCtor { // expected-note 2{{no constexpr constructors}}
constexpr ConstexprCtor(P...); // expected-note {{constructor template instantiation is not constexpr because 1st parameter type 'NonLiteral' is not a literal type}} \
expected-note {{constructor template instantiation is not constexpr because 2nd parameter type 'NonLiteral' is not a literal type}}
template<typename ...P> struct ConstexprCtor {
constexpr ConstexprCtor(P...) {}
};
constexpr ConstexprCtor<> f1(); // ok
constexpr ConstexprCtor<int> f2(); // ok
constexpr ConstexprCtor<NonLiteral> f3(); // expected-error {{not a literal type}}
constexpr ConstexprCtor<int, NonLiteral> f4(); // expected-error {{not a literal type}}
constexpr ConstexprCtor<> f1() { return {}; } // ok
constexpr ConstexprCtor<int> f2() { return 0; } // ok
constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
struct VirtBase : virtual S {}; // expected-note {{here}}
namespace TemplateVBase {
template<typename T> struct T1 : virtual Literal { // expected-note {{here}}
constexpr T1(); // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
constexpr T1() {} // expected-error {{constexpr constructor not allowed in struct with virtual base class}}
};
template<typename T> struct T2 : virtual T { // expected-note {{struct with virtual base class is not a literal type}} expected-note {{here}}
template<typename T> struct T2 : virtual T {
// FIXME: This is ill-formed (no diagnostic required).
// We should diagnose it now rather than waiting until instantiation.
constexpr T2(); // desired-error {{constexpr constructor not allowed in class with virtual base classes}}
constexpr T2() {}
};
constexpr T2<Literal> g2(); // expected-error {{not a literal type}}
constexpr T2<Literal> g2() { return {}; }
template<typename T> class T3 : public T { // expected-note {{class with virtual base class is not a literal type}}
public:
constexpr T3() {}
};
constexpr T3<Literal> g3(); // ok
constexpr T3<VirtBase> g4(); // expected-error {{not a literal type}}
constexpr T3<Literal> g3() { return {}; } // ok
constexpr T3<VirtBase> g4() { return {}; } // expected-error {{not a literal type}}
}

View File

@ -18,15 +18,15 @@ extern int (*const d)(int);
// A variable declaration which uses the constexpr specifier shall have an
// initializer and shall be initialized by a constant expression.
constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}}
constexpr struct C { C(); } ni2; // expected-error {{constexpr variable 'ni2' must be initialized by a constant expression}} expected-note {{non-literal type 'const struct C' cannot be used in a constant expression}}
constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}}
constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}}
constexpr int nc1 = i; // expected-error {{constexpr variable 'nc1' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
constexpr C nc2 = C(); // expected-error {{constexpr variable 'nc2' must be initialized by a constant expression}} expected-note {{non-literal type}}
constexpr C nc2 = C(); // expected-error {{cannot have non-literal type 'const C'}}
int &f(); // expected-note {{declared here}}
constexpr int &nc3 = f(); // expected-error {{constexpr variable 'nc3' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}}
constexpr int nc4(i); // expected-error {{constexpr variable 'nc4' must be initialized by a constant expression}} expected-note {{read of non-const variable 'i' is not allowed in a constant expression}}
constexpr C nc5((C())); // expected-error {{constexpr variable 'nc5' must be initialized by a constant expression}} expected-note {{non-literal type 'const C'}}
constexpr C nc5((C())); // expected-error {{cannot have non-literal type 'const C'}}
int &f(); // expected-note {{here}}
constexpr int &nc6(f()); // expected-error {{constexpr variable 'nc6' must be initialized by a constant expression}} expected-note {{non-constexpr function 'f'}}

View File

@ -288,7 +288,7 @@ namespace LValueToRValue {
// non-volatile const object with a preceding initialization, initialized
// with a constant expression [Note: a string literal (2.14.5 [lex.string])
// corresponds to an array of such objects. -end note], or
volatile const int vi = 1; // expected-note {{here}}
volatile const int vi = 1; // expected-note 2{{here}}
const int ci = 1;
volatile const int &vrci = ci;
static_assert(vi, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
@ -298,18 +298,23 @@ namespace LValueToRValue {
// - a non-volatile glvalue of literal type that refers to a non-volatile
// object defined with constexpr, or that refers to a sub-object of such an
// object, or
struct S {
constexpr S(int=0) : i(1), v(1) {}
constexpr S(const S &s) : i(2), v(2) {}
int i;
volatile int v; // expected-note {{here}}
struct V {
constexpr V() : v(1) {}
volatile int v; // expected-note {{not literal because}}
};
constexpr S s;
constexpr V v; // expected-error {{non-literal type}}
struct S {
constexpr S(int=0) : i(1), v(const_cast<volatile int&>(vi)) {}
constexpr S(const S &s) : i(2), v(const_cast<volatile int&>(vi)) {}
int i;
volatile int &v;
};
constexpr S s; // ok
constexpr volatile S vs; // expected-note {{here}}
constexpr const volatile S &vrs = s;
constexpr const volatile S &vrs = s; // ok
static_assert(s.i, "");
static_assert(s.v, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
static_assert(const_cast<int&>(s.v), ""); // expected-error {{constant expression}} expected-note {{read of volatile member 'v'}}
static_assert(const_cast<int&>(s.v), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vi'}}
static_assert(vs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
static_assert(const_cast<int&>(vs.i), ""); // expected-error {{constant expression}} expected-note {{read of volatile object 'vs'}}
static_assert(vrs.i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}

View File

@ -11,7 +11,7 @@ struct NonConstexpr2 { // expected-note {{here}}
struct NonConstexpr2a : NonConstexpr1 { };
constexpr NonConstexpr1 nc1 = NonConstexpr1(); // ok, does not call constructor
constexpr NonConstexpr2 nc2 = NonConstexpr2(); // ok, does not call constructor
constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr2a'}}
constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // ok, does not call constructor
constexpr int nc2_a = NonConstexpr2().nl.a; // ok
constexpr int nc2a_a = NonConstexpr2a().a; // ok
struct Helper {
@ -21,8 +21,8 @@ struct Helper {
struct Constexpr1 {};
constexpr Constexpr1 c1 = Constexpr1(); // ok
struct NonConstexpr3 : virtual Constexpr1 {};
constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr3'}}
struct NonConstexpr3 : virtual Constexpr1 {}; // expected-note {{struct with virtual base}} expected-note {{declared here}}
constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{non-literal type 'const NonConstexpr3'}}
struct Constexpr2 {
int a = 0;

View File

@ -26,6 +26,6 @@ struct D : C { int d; };
constexpr C c1; // expected-error {{requires a user-provided default constructor}}
constexpr C c2 = C(); // ok
constexpr D d1; // expected-error {{requires a user-provided default constructor}}
constexpr D d2 = D(); // expected-error {{constant expression}} expected-note {{non-literal type 'const D'}}
constexpr D d2 = D(); // ok with DR1452
static_assert(D().c == 0, "");
static_assert(D().d == 0, "");

View File

@ -23,6 +23,8 @@ static_assert(__is_literal(VectorExt), "fail");
// a constant expression,
// -- it is an aggregate type or has at least one constexpr constructor
// or constructor template that is not a copy or move constructor, and
// [DR1452 adds class types with trivial default constructors to
// this list]
// -- it has all non-static data members and base classes of literal
// types
struct Empty {};
@ -36,25 +38,26 @@ struct LiteralType {
struct HasDtor { ~HasDtor(); };
class NonAggregate { int x; };
struct HasNonLiteralBase : NonAggregate {};
struct NonLiteral { NonLiteral(); };
struct HasNonLiteralBase : NonLiteral {};
struct HasNonLiteralMember { HasDtor x; };
static_assert(__is_literal(Empty), "fail");
static_assert(__is_literal(LiteralType), "fail");
static_assert(__is_literal(NonAggregate), "fail");
static_assert(!__is_literal(NonLiteral), "fail");
static_assert(!__is_literal(HasDtor), "fail");
static_assert(!__is_literal(NonAggregate), "fail");
static_assert(!__is_literal(HasNonLiteralBase), "fail");
static_assert(!__is_literal(HasNonLiteralMember), "fail");
// FIXME: Test constexpr constructors and non-static members with initializers
// when Clang supports them:
#if 0
extern int f();
// DR1361 removes the brace-or-equal-initializer bullet so that we can allow:
extern int f(); // expected-note {{here}}
struct HasNonConstExprMemInit {
int x = f();
constexpr HasNonConstExprMemInit(int y) {}
int x = f(); // expected-note {{non-constexpr function}}
constexpr HasNonConstExprMemInit() {} // expected-error {{never produces a constant expression}}
constexpr HasNonConstExprMemInit(int y) : x(y) {} // ok
};
static_assert(!__is_literal(HasNonConstExprMemInit), "fail");
static_assert(__is_literal(HasNonConstExprMemInit), "fail");
class HasConstExprCtor {
int x;
@ -66,6 +69,9 @@ template <typename T> class HasConstExprCtorTemplate {
public:
template <typename U> constexpr HasConstExprCtorTemplate(U y) : x(y) {}
};
template <typename T> class HasConstExprCtorT {
constexpr HasConstExprCtorT(T) {}
};
static_assert(__is_literal(HasConstExprCtor), "fail");
static_assert(__is_literal(HasConstExprCtorTemplate), "fail");
#endif
static_assert(__is_literal(HasConstExprCtorTemplate<int>), "fail");
static_assert(__is_literal(HasConstExprCtorT<NonLiteral>), "fail");