forked from OSchip/llvm-project
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:
parent
779579b332
commit
3607ffee5c
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
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,10 +684,7 @@ 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.
|
||||
|
@ -723,26 +694,19 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD,
|
|||
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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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, "");
|
||||
|
|
|
@ -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'.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
|
@ -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'}}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, "");
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue