[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