<div class="gmail_quote">On Thu, Sep 29, 2011 at 12:11 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Author: rsmith<br>
Date: Thu Sep 29 14:11:37 2011<br>
New Revision: 140801<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=140801&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=140801&view=rev</a><br>
Log:<br>
constexpr: semantic checking for constexpr variables.<br>
<br>
We had an extension which allowed const static class members of floating-point type to have in-class initializers, 'as a C++0x extension'. However, C++0x does not allow this. The extension has been kept, and extended to all literal types in C++0x mode (with a fixit to add the 'constexpr' specifier).<br>
<br>
Added:<br>
cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp<br>
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp<br>
Modified:<br>
cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
cfe/trunk/lib/Sema/SemaDecl.cpp<br>
cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp<br>
cfe/trunk/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp<br>
cfe/trunk/test/FixIt/fixit-cxx0x.cpp<br>
cfe/trunk/test/SemaCXX/class.cpp<br>
cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Sep 29 14:11:37 2011<br>
@@ -303,9 +303,7 @@<br>
<br>
// A warning group for warnings about using C++0x features as extensions in<br>
// earlier C++ versions.<br>
-def CXX0xStaticNonIntegralInitializer :<br>
- DiagGroup<"c++0x-static-nonintegral-init">;<br>
-def CXX0x : DiagGroup<"c++0x-extensions", [CXX0xStaticNonIntegralInitializer]>;<br>
+def CXX0x : DiagGroup<"c++0x-extensions">;<br></blockquote><div><br></div><div>This could really use a better name than 'CXX0x'...</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
def DelegatingCtorCycles :<br>
DiagGroup<"delegating-ctor-cycles">;<br>
<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Sep 29 14:11:37 2011<br>
@@ -1186,7 +1186,15 @@<br>
def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;<br>
def err_constexpr_no_declarators : Error<<br>
"constexpr can only be used in variable and function declarations">;<br>
-<br>
+def err_invalid_constexpr_var_decl : Error<<br>
+ "constexpr variable declaration must be a definition">;<br>
+def err_constexpr_var_requires_init : Error<<br>
+ "declaration of constexpr variable %0 requires an initializer">;<br>
+def err_constexpr_initialized_static_member : Error<<br>
+ "definition of initialized static data member %0 cannot be marked constexpr">;<br>
+def err_constexpr_var_requires_const_init : Error<<br>
+ "constexpr variable %0 must be initialized by a constant expression">;<br>
+<br>
// Objective-C++<br>
def err_objc_decls_may_only_appear_in_global_scope : Error<<br>
"Objective-C declarations may only appear in global scope">;<br>
@@ -4072,8 +4080,12 @@<br>
def err_in_class_initializer_bad_type : Error<<br>
"static data member of type %0 must be initialized out of line">;<br>
def ext_in_class_initializer_float_type : ExtWarn<<br>
- "in-class initializer for static data member of type %0 "<br>
- "is a C++0x extension">, InGroup<CXX0xStaticNonIntegralInitializer>;<br>
+ "in-class initializer for static data member of type %0 not allowed, "<br>
+ "accepted as an extension">, InGroup<DiagGroup<"static-member-init">>;<br>
+def ext_in_class_initializer_literal_type : ExtWarn<<br>
+ "in-class initializer for static data member of type %0 requires "<br>
+ "'constexpr' specifier, accepted as an extension">,<br>
+ InGroup<DiagGroup<"static-member-init">>;<br>
def err_in_class_initializer_non_constant : Error<<br>
"in-class initializer is not a constant expression">;<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Sep 29 14:11:37 2011<br>
@@ -3833,8 +3833,36 @@<br>
}<br>
<br>
if (D.getDeclSpec().isConstexprSpecified()) {<br>
- // FIXME: check this is a valid use of constexpr.<br>
- NewVD->setConstexpr(true);<br>
+ // FIXME: once we know whether there's an initializer, apply this to<br>
+ // static data members too.<br>
+ if (!NewVD->isStaticDataMember() &&<br>
+ !NewVD->isThisDeclarationADefinition()) {<br>
+ // 'constexpr' is redundant and ill-formed on a non-defining declaration<br>
+ // of a variable. Suggest replacing it with 'const' if appropriate.<br>
+ SourceLocation ConstexprLoc = D.getDeclSpec().getConstexprSpecLoc();<br>
+ SourceRange ConstexprRange(ConstexprLoc, ConstexprLoc);<br>
+ // If the declarator is complex, we need to move the keyword to the<br>
+ // innermost chunk as we switch it from 'constexpr' to 'const'.<br>
+ int Kind = DeclaratorChunk::Paren;<br>
+ for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) {<br>
+ Kind = D.getTypeObject(I).Kind;<br>
+ if (Kind != DeclaratorChunk::Paren)<br>
+ break;<br>
+ }<br>
+ if ((D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const) ||<br>
+ Kind == DeclaratorChunk::Reference)<br>
+ Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)<br>
+ << FixItHint::CreateRemoval(ConstexprRange);<br>
+ else if (Kind == DeclaratorChunk::Paren)<br>
+ Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)<br>
+ << FixItHint::CreateReplacement(ConstexprRange, "const");<br>
+ else<br>
+ Diag(ConstexprLoc, diag::err_invalid_constexpr_var_decl)<br>
+ << FixItHint::CreateRemoval(ConstexprRange)<br>
+ << FixItHint::CreateInsertion(D.getIdentifierLoc(), "const ");<br>
+ } else {<br>
+ NewVD->setConstexpr(true);<br>
+ }<br>
}<br>
}<br>
<br>
@@ -5796,11 +5824,26 @@<br>
// A member-declarator can contain a constant-initializer only<br>
// if it declares a static member (9.4) of const integral or<br>
// const enumeration type, see 9.4.2.<br>
+ //<br>
+ // C++0x [class.static.data]p3:<br>
+ // If a non-volatile const static data member is of integral or<br>
+ // enumeration type, its declaration in the class definition can<br>
+ // specify a brace-or-equal-initializer in which every initalizer-clause<br>
+ // that is an assignment-expression is a constant expression. A static<br>
+ // data member of literal type can be declared in the class definition<br>
+ // with the constexpr specifier; if so, its declaration shall specify a<br>
+ // brace-or-equal-initializer in which every initializer-clause that is<br>
+ // an assignment-expression is a constant expression.<br>
QualType T = VDecl->getType();<br>
<br>
// Do nothing on dependent types.<br>
if (T->isDependentType()) {<br>
<br>
+ // Allow any 'static constexpr' members, whether or not they are of literal<br>
+ // type. We separately check that the initializer is a constant expression,<br>
+ // which implicitly requires the member to be of literal type.<br>
+ } else if (VDecl->isConstexpr()) {<br>
+<br>
// Require constness.<br>
} else if (!T.isConstQualified()) {<br>
Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)<br>
@@ -5809,6 +5852,9 @@<br>
<br>
// We allow integer constant expressions in all cases.<br>
} else if (T->isIntegralOrEnumerationType()) {<br>
+ // FIXME: In C++0x, a non-constexpr const static data member with an<br>
+ // in-class initializer cannot be volatile.<br>
+<br>
// Check whether the expression is a constant expression.<br>
SourceLocation Loc;<br>
if (Init->isValueDependent())<br>
@@ -5828,31 +5874,28 @@<br>
VDecl->setInvalidDecl();<br>
}<br>
<br>
- // We allow floating-point constants as an extension in C++03, and<br>
- // C++0x has far more complicated rules that we don't really<br>
- // implement fully.<br>
- } else {<br>
- bool Allowed = false;<br>
- if (getLangOptions().CPlusPlus0x) {<br>
- Allowed = T->isLiteralType();<br>
- } else if (T->isFloatingType()) { // also permits complex, which is ok<br>
- Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)<br>
- << T << Init->getSourceRange();<br>
- Allowed = true;<br>
- }<br>
+ // Suggest adding 'constexpr' in C++0x for literal types.<br>
+ } else if (getLangOptions().CPlusPlus0x && T->isLiteralType()) {<br>
+ Diag(VDecl->getLocation(), diag::ext_in_class_initializer_literal_type)<br>
+ << T << Init->getSourceRange()<br>
+ << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");<br></blockquote><div><br></div><div>This FixItHint needs to be on a note, rather than the ext-warn; we don't recover here by parsing this *as* a constexpr (nor would that be entirely appropriate I suspect)...</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
+ VDecl->setConstexpr(true);<br>
+<br>
+ // We allow floating-point constants as an extension.<br>
+ } else if (T->isFloatingType()) { // also permits complex, which is ok<br>
+ Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)<br>
+ << T << Init->getSourceRange();<br>
<br>
- if (!Allowed) {<br>
- Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)<br>
- << T << Init->getSourceRange();<br>
- VDecl->setInvalidDecl();<br>
-<br>
- // TODO: there are probably expressions that pass here that shouldn't.<br>
- } else if (!Init->isValueDependent() &&<br>
- !Init->isConstantInitializer(Context, false)) {<br>
+ if (!Init->isValueDependent() &&<br>
+ !Init->isConstantInitializer(Context, false)) {<br>
Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)<br>
<< Init->getSourceRange();<br>
VDecl->setInvalidDecl();<br>
}<br>
+ } else {<br>
+ Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type)<br>
+ << T << Init->getSourceRange();<br>
+ VDecl->setInvalidDecl();<br>
}<br>
} else if (VDecl->isFileVarDecl()) {<br>
if (VDecl->getStorageClassAsWritten() == SC_Extern &&<br>
@@ -5893,6 +5936,17 @@<br>
<br>
if (!VDecl->isInvalidDecl())<br>
checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);<br>
+<br>
+ if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&<br>
+ !VDecl->getType()->isDependentType() &&<br>
+ !Init->isTypeDependent() && !Init->isValueDependent() &&<br>
+ !Init->isConstantInitializer(Context,<br>
+ VDecl->getType()->isReferenceType())) {<br>
+ // FIXME: Improve this diagnostic to explain why the initializer is not<br>
+ // a constant expression.<br>
+ Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init)<br>
+ << VDecl << Init->getSourceRange();<br>
+ }<br>
<br>
Init = MaybeCreateExprWithCleanups(Init);<br>
// Attach the initializer to the decl.<br>
@@ -5958,6 +6012,24 @@<br>
return;<br>
}<br>
<br>
+ // C++0x [dcl.constexpr]p9: An object or reference declared constexpr must<br>
+ // have an initializer.<br>
+ // C++0x [class.static.data]p3: A static data member can be declared with<br>
+ // the constexpr specifier; if so, its declaration shall specify<br>
+ // a brace-or-equal-initializer.<br>
+ if (Var->isConstexpr()) {<br>
+ // FIXME: Provide fix-its to convert the constexpr to const.<br>
+ if (Var->isStaticDataMember() && Var->getAnyInitializer()) {<br>
+ Diag(Var->getLocation(), diag::err_constexpr_initialized_static_member)<br>
+ << Var->getDeclName();<br>
+ } else {<br>
+ Diag(Var->getLocation(), diag::err_constexpr_var_requires_init)<br>
+ << Var->getDeclName();<br>
+ }<br>
+ Var->setInvalidDecl();<br>
+ return;<br>
+ }<br>
+<br>
switch (Var->isThisDeclarationADefinition()) {<br>
case VarDecl::Definition:<br>
if (!Var->isStaticDataMember() || !Var->getAnyInitializer())<br>
@@ -6151,9 +6223,8 @@<br>
case SC_OpenCLWorkGroupLocal:<br>
llvm_unreachable("Unexpected storage class");<br>
}<br>
- // FIXME: constexpr isn't allowed here.<br>
- //if (DS.isConstexprSpecified())<br>
- // Error = 5;<br>
+ if (VD->isConstexpr())<br>
+ Error = 5;<br>
if (Error != -1) {<br>
Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class)<br>
<< VD->getDeclName() << Error;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Sep 29 14:11:37 2011<br>
@@ -1239,14 +1239,8 @@<br>
if (Init)<br>
AddInitializerToDecl(Member, Init, false,<br>
DS.getTypeSpecType() == DeclSpec::TST_auto);<br>
- else if (DS.getTypeSpecType() == DeclSpec::TST_auto &&<br>
- DS.getStorageClassSpec() == DeclSpec::SCS_static) {<br>
- // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static<br>
- // data member if a brace-or-equal-initializer is provided.<br>
- Diag(Loc, diag::err_auto_var_requires_init)<br>
- << Name << cast<ValueDecl>(Member)->getType();<br>
- Member->setInvalidDecl();<br>
- }<br>
+ else if (DS.getStorageClassSpec() == DeclSpec::SCS_static)<br>
+ ActOnUninitializedDecl(Member, DS.getTypeSpecType() == DeclSpec::TST_auto);<br>
<br>
FinalizeDeclaration(Member);<br>
<br>
@@ -8727,10 +8721,21 @@<br>
return;<br>
}<br>
<br>
- CheckImplicitConversions(Result.get(), LParenLoc);<br>
+ Expr *Init = Result.get();<br>
+ CheckImplicitConversions(Init, LParenLoc);<br>
<br>
- Result = MaybeCreateExprWithCleanups(Result);<br>
- VDecl->setInit(Result.takeAs<Expr>());<br>
+ if (VDecl->isConstexpr() && !VDecl->isInvalidDecl() &&<br>
+ !Init->isValueDependent() &&<br>
+ !Init->isConstantInitializer(Context,<br>
+ VDecl->getType()->isReferenceType())) {<br>
+ // FIXME: Improve this diagnostic to explain why the initializer is not<br>
+ // a constant expression.<br>
+ Diag(VDecl->getLocation(), diag::err_constexpr_var_requires_const_init)<br>
+ << VDecl << Init->getSourceRange();<br>
+ }<br>
+<br>
+ Init = MaybeCreateExprWithCleanups(Init);<br>
+ VDecl->setInit(Init);<br>
VDecl->setCXXDirectInitializer(true);<br>
<br>
CheckCompleteVariableDeclaration(VDecl);<br>
<br>
Added: cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp?rev=140801&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp?rev=140801&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp (added)<br>
+++ cfe/trunk/test/CXX/class/class.static/class.static.data/p3.cpp Thu Sep 29 14:11:37 2011<br>
@@ -0,0 +1,24 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s<br>
+<br>
+struct NonLit {<br>
+ NonLit();<br>
+};<br>
+<br>
+struct S {<br>
+ static constexpr int a = 0;<br>
+ static constexpr int b; // expected-error {{declaration of constexpr variable 'b' requires an initializer}}<br>
+<br>
+ static constexpr int c = 0;<br>
+ static const int d;<br>
+<br>
+ static constexpr double e = 0.0; // ok<br>
+ static const double f = 0.0; // expected-warning {{accepted as an extension}}<br>
+ static char *const g = 0; // expected-warning {{accepted as an extension}}<br>
+ static const NonLit h = NonLit(); // expected-error {{must be initialized out of line}}<br>
+};<br>
+<br>
+constexpr int S::a; // expected-error {{definition of initialized static data member 'a' cannot be marked constexpr}}<br>
+constexpr int S::b = 0;<br>
+<br>
+const int S::c;<br>
+constexpr int S::d = 0;<br>
<br>
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp (original)<br>
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp Thu Sep 29 14:11:37 2011<br>
@@ -11,19 +11,22 @@<br>
constexpr int i1 = 0;<br>
constexpr int f1() { return 0; }<br>
struct s1 {<br>
- constexpr static int mi = 0;<br>
+ constexpr static int mi1 = 0;<br>
+ const static int mi2;<br>
};<br>
+constexpr int s1::mi2 = 0;<br>
<br>
// invalid declarations<br>
// not a definition of an object<br>
-constexpr extern int i2; // x<br>
+constexpr extern int i2; // expected-error {{constexpr variable declaration must be a definition}}<br>
// not a literal type<br>
-constexpr notlit nl1; // x<br>
+constexpr notlit nl1; // expected-error {{declaration of constexpr variable 'nl1' requires an initializer}}<br>
// function parameters<br>
void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}<br>
// non-static member<br>
struct s2 {<br>
- constexpr int mi; // expected-error {{non-static data member cannot be constexpr}}<br>
+ constexpr int mi1; // expected-error {{non-static data member cannot be constexpr}}<br>
+ static constexpr int mi2; // expected-error {{requires an initializer}}<br>
};<br>
// typedef<br>
typedef constexpr int CI; // expected-error {{typedef cannot be constexpr}}<br>
@@ -63,7 +66,8 @@<br>
template <><br>
notlit ft(notlit nl) { return nl; }<br>
<br>
-constexpr int i3 = ft(1);<br>
+// FIXME: The initializer is a constant expression.<br>
+constexpr int i3 = ft(1); // unexpected-error {{must be initialized by a constant expression}}<br>
<br>
void test() {<br>
// ignore constexpr when instantiating with non-literal<br>
@@ -85,17 +89,17 @@<br>
: x(square(a)), y(square(a))<br>
{ }<br>
<br>
-constexpr pixel small(2); // x (no definition of square(int) yet, so can't<br>
- // constexpr-eval pixel(int))<br>
+constexpr pixel small(2); // expected-error {{must be initialized by a constant expression}}<br>
<br>
constexpr int square(int x) {<br>
return x * x;<br>
}<br>
<br>
-constexpr pixel large(4); // now valid<br>
+// FIXME: The initializer is a constant expression.<br>
+constexpr pixel large(4); // unexpected-error {{must be initialized by a constant expression}}<br>
<br>
int next(constexpr int x) { // expected-error {{function parameter cannot be constexpr}}<br>
return x + 1;<br>
}<br>
<br>
-extern constexpr int memsz; // x<br>
+extern constexpr int memsz; // expected-error {{constexpr variable declaration must be a definition}}<br>
<br>
Added: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp?rev=140801&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp?rev=140801&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp (added)<br>
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp Thu Sep 29 14:11:37 2011<br>
@@ -0,0 +1,37 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s<br>
+<br>
+// A constexpr specifier used in an object declaration declares the object as<br>
+// const.<br>
+constexpr int a = 0;<br>
+extern const int a;<br>
+<br>
+int i;<br>
+constexpr int *b = &i;<br>
+extern int *const b;<br>
+<br>
+constexpr int &c = i;<br>
+extern int &c;<br>
+<br>
+constexpr int (*d)(int) = 0;<br>
+extern int (*const d)(int);<br>
+<br>
+// A variable declaration which uses the constexpr specifier shall have an<br>
+// initializer and shall be initialized by a constant expression.<br>
+constexpr int ni1; // expected-error {{declaration of constexpr variable 'ni1' requires an initializer}}<br>
+constexpr struct C { C(); } ni2; // expected-error {{declaration of constexpr variable 'ni2' requires an initializer}}<br>
+constexpr double &ni3; // expected-error {{declaration of constexpr variable 'ni3' requires an initializer}}<br>
+<br>
+constexpr int nc1 = i; // expected-error {{constexpr variable 'nc1' must be initialized by a constant expression}}<br>
+constexpr C nc2 = C(); // expected-error {{constexpr variable 'nc2' must be initialized by a constant expression}}<br>
+int &f();<br>
+constexpr int &nc3 = f(); // expected-error {{constexpr variable 'nc3' must be initialized by a constant expression}}<br>
+constexpr int nc4(i); // expected-error {{constexpr variable 'nc4' must be initialized by a constant expression}}<br>
+constexpr C nc5((C())); // expected-error {{constexpr variable 'nc5' must be initialized by a constant expression}}<br>
+int &f();<br>
+constexpr int &nc6(f()); // expected-error {{constexpr variable 'nc6' must be initialized by a constant expression}}<br>
+<br>
+struct pixel {<br>
+ int x, y;<br>
+};<br>
+constexpr pixel ur = { 1294, 1024 }; // ok<br>
+constexpr pixel origin; // expected-error {{requires an initializer}}<br>
<br>
Modified: cfe/trunk/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp (original)<br>
+++ cfe/trunk/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp Thu Sep 29 14:11:37 2011<br>
@@ -100,8 +100,7 @@<br>
for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}<br>
for (static int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'static'}}<br>
for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}<br>
- // FIXME: when clang supports constexpr, this should be rejected.<br>
- for (constexpr int a : A()) {} // desired-error {{loop variable 'a' may not be declared 'constexpr'}}<br>
+ for (constexpr int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'constexpr'}}<br>
<br>
struct NoBeginADL {<br>
null_t alt_end();<br>
<br>
Modified: cfe/trunk/test/FixIt/fixit-cxx0x.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-cxx0x.cpp?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-cxx0x.cpp?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/FixIt/fixit-cxx0x.cpp (original)<br>
+++ cfe/trunk/test/FixIt/fixit-cxx0x.cpp Thu Sep 29 14:11:37 2011<br>
@@ -1,6 +1,6 @@<br>
// RUN: %clang_cc1 -verify -std=c++0x %s<br>
// RUN: cp %s %t<br>
-// RUN: not %clang_cc1 -x c++ -std=c++0x -fixit %t<br>
+// RUN: not %clang_cc1 -x c++ -std=c++0x -Werror -fixit %t<br>
// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++0x %t<br>
<br>
/* This is a test of the various code modification hints that only<br>
@@ -17,3 +17,45 @@<br>
using ::T = void; // expected-error {{name defined in alias declaration must be an identifier}}<br>
using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}<br>
using typename ::V = void; // expected-error {{name defined in alias declaration must be an identifier}}<br>
+<br>
+namespace Constexpr {<br>
+ extern constexpr int a; // expected-error {{must be a definition}}<br>
+ // -> extern const int a;<br>
+<br>
+ extern constexpr int *b; // expected-error {{must be a definition}}<br>
+ // -> extern int *const b;<br>
+<br>
+ extern constexpr int &c; // expected-error {{must be a definition}}<br>
+ // -> extern int &b;<br>
+<br>
+ extern constexpr const int d; // expected-error {{must be a definition}}<br>
+ // -> extern const int d;<br>
+<br>
+ int z;<br>
+ constexpr int a = 0;<br>
+ constexpr int *b = &z;<br>
+ constexpr int &c = z;<br>
+ constexpr int d = a;<br>
+<br>
+ // FIXME: Provide FixIts for static data members too.<br>
+#if 0<br>
+ struct S {<br>
+ static constexpr int a = 0;<br>
+<br>
+ static constexpr int b; // xpected-error {{requires an initializer}}<br>
+ // -> const int b;<br>
+ };<br>
+<br>
+ constexpr int S::a; // xpected-error {{requires an initializer}}<br>
+ // -> const int S::a;<br>
+<br>
+ constexpr int S::b = 0;<br>
+#endif<br>
+<br>
+ struct S {<br>
+ static const double d = 0.0; // expected-warning {{accepted as an extension}}<br>
+ // -> constexpr static const double d = 0.0;<br>
+ static char *const p = 0; // expected-warning {{accepted as an extension}}<br>
+ // -> constexpr static char *const p = 0;<br>
+ };<br>
+}<br>
<br>
Modified: cfe/trunk/test/SemaCXX/class.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/class.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/class.cpp Thu Sep 29 14:11:37 2011<br>
@@ -172,8 +172,8 @@<br>
float foo();<br>
<br>
struct A {<br>
- static const float x = 5.0f; // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}}<br>
- static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' is a C++0x extension}} expected-error {{in-class initializer is not a constant expression}}<br>
+ static const float x = 5.0f; // expected-warning {{in-class initializer for static data member of type 'const float' not allowed}}<br>
+ static const float y = foo(); // expected-warning {{in-class initializer for static data member of type 'const float' not allowed}} expected-error {{in-class initializer is not a constant expression}}<br>
};<br>
}<br>
<br>
<br>
Modified: cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp?rev=140801&r1=140800&r2=140801&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp?rev=140801&r1=140800&r2=140801&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp (original)<br>
+++ cfe/trunk/test/SemaTemplate/instantiate-static-var.cpp Thu Sep 29 14:11:37 2011<br>
@@ -11,7 +11,7 @@<br>
<br>
template<typename T><br>
class Y {<br>
- static const T value = 0; // expected-warning{{in-class initializer for static data member of type 'const float' is a C++0x extension}}<br>
+ static const T value = 0; // expected-warning{{in-class initializer for static data member of type 'const float' not allowed, accepted as an extension}}<br>
};<br>
<br>
Y<float> fy; // expected-note{{in instantiation of template class 'Y<float>' requested here}}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>