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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140801 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp
new file mode 100644
index 0000000..72dbec7
--- /dev/null
+++ b/test/CXX/class/class.static/class.static.data/p3.cpp
@@ -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;
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
index d9b09c6..e1911a2 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -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}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
new file mode 100644
index 0000000..9b2120c
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
@@ -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}}
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 19398ae..d842bff 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -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();
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index c3c1dcf..2addad4 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -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;
+ };
+}
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index fd2d0b3..4071d1f 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -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}}
};
}
diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp
index 0c06075..723cbd3 100644
--- a/test/SemaTemplate/instantiate-static-var.cpp
+++ b/test/SemaTemplate/instantiate-static-var.cpp
@@ -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}}