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