[cfe-commits] r150359 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Sema/ test/CXX/basic/basic.types/ test/CXX/class/class.static/class.static.data/ test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/ test/CXX/expr/expr.const/ test/CXX/special/class.ctor/ test/SemaCXX/
Richard Smith
richard-llvm at metafoo.co.uk
Sun Feb 12 19:54:03 PST 2012
Author: rsmith
Date: Sun Feb 12 21:54:03 2012
New Revision: 150359
URL: http://llvm.org/viewvc/llvm-project?rev=150359&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/CXX/basic/basic.types/p10.cpp
cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp
cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
cfe/trunk/test/SemaCXX/literal-type.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Sun Feb 12 21:54:03 2012
@@ -469,7 +469,8 @@
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 @@
// (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 @@
// 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();
}
Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Sun Feb 12 21:54:03 2012
@@ -28,6 +28,11 @@
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<
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Feb 12 21:54:03 2012
@@ -1361,6 +1361,8 @@
"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 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_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<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun Feb 12 21:54:03 2012
@@ -835,8 +835,7 @@
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 @@
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
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Feb 12 21:54:03 2012
@@ -799,8 +799,8 @@
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()) {
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Feb 12 21:54:03 2012
@@ -2033,6 +2033,12 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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;
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Feb 12 21:54:03 2012
@@ -3991,8 +3991,15 @@
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 @@
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 @@
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 @@
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");
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Feb 12 21:54:03 2012
@@ -632,9 +632,9 @@
// 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 @@
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.
-//
-// This implements C++11 [dcl.constexpr]p3,4, as amended by N3308.
+// the requirements of a constexpr function definition or a constexpr
+// constructor definition. If so, return true. If not, produce appropriate
+// diagnostics and return false.
//
-// \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 @@
// - 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);
-
- // 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);
- }
+ 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);
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 @@
/// 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 @@
// - 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 @@
// 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 @@
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:
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sun Feb 12 21:54:03 2012
@@ -1034,7 +1034,7 @@
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 @@
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 @@
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 @@
D->isStatic(),
D->getStorageClassAsWritten(),
D->isInlineSpecified(),
- /*isConstexpr*/ false, D->getLocEnd());
+ D->isConstexpr(), D->getLocEnd());
}
if (QualifierLoc)
@@ -2305,13 +2305,6 @@
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.
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sun Feb 12 21:54:03 2012
@@ -4243,19 +4243,14 @@
/// @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 @@
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 @@
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 @@
}
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;
}
}
Modified: cfe/trunk/test/CXX/basic/basic.types/p10.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.types/p10.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.types/p10.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.types/p10.cpp Sun Feb 12 21:54:03 2012
@@ -5,22 +5,23 @@
// 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 @@
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 @@
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 @@
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 @@
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}}
Modified: cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp (original)
+++ cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp Sun Feb 12 21:54:03 2012
@@ -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 @@
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, "");
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp Sun Feb 12 21:54:03 2012
@@ -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 @@
// 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 @@
// 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'.
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp Sun Feb 12 21:54:03 2012
@@ -8,7 +8,7 @@
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 @@
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 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
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp Sun Feb 12 21:54:03 2012
@@ -18,16 +18,12 @@
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 @@
// - 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}}
};
}
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp Sun Feb 12 21:54:03 2012
@@ -10,7 +10,7 @@
struct NonLiteral {
NonLiteral() {}
- NonLiteral(int) {}
+ NonLiteral(int) {} // expected-note 2{{here}}
operator int() const { return 0; }
};
struct Literal {
@@ -19,7 +19,7 @@
};
struct S {
- virtual int ImplicitlyVirtual();
+ virtual int ImplicitlyVirtual() const;
};
struct T {};
@@ -27,48 +27,42 @@
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
-
-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}}
-};
-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 int d = ConstexprMember<int>().F(); // ok
+constexpr int e = ConstexprMember<NonLiteral>().F(); // expected-error {{constant expression}}
+
+template<typename ...P> struct ConstexprCtor {
+ constexpr ConstexprCtor(P...) {}
+};
+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}}
}
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp Sun Feb 12 21:54:03 2012
@@ -18,15 +18,15 @@
// 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'}}
Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Sun Feb 12 21:54:03 2012
@@ -288,7 +288,7 @@
// 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 @@
// - 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 V {
+ constexpr V() : v(1) {}
+ volatile int v; // expected-note {{not literal because}}
+ };
+ constexpr V v; // expected-error {{non-literal type}}
struct S {
- constexpr S(int=0) : i(1), v(1) {}
- constexpr S(const S &s) : i(2), v(2) {}
+ 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; // expected-note {{here}}
+ volatile int &v;
};
- constexpr S s;
+ 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}}
Modified: cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.ctor/p6-0x.cpp Sun Feb 12 21:54:03 2012
@@ -11,7 +11,7 @@
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 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;
Modified: cfe/trunk/test/SemaCXX/constexpr-value-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-value-init.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-value-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-value-init.cpp Sun Feb 12 21:54:03 2012
@@ -26,6 +26,6 @@
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, "");
Modified: cfe/trunk/test/SemaCXX/literal-type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/literal-type.cpp?rev=150359&r1=150358&r2=150359&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/literal-type.cpp (original)
+++ cfe/trunk/test/SemaCXX/literal-type.cpp Sun Feb 12 21:54:03 2012
@@ -23,6 +23,8 @@
// 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 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 @@
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");
More information about the cfe-commits
mailing list