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}}