]> granicus.if.org Git - clang/commitdiff
constexpr: static data members declared constexpr are required to have an
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 7 Nov 2011 22:16:17 +0000 (22:16 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 7 Nov 2011 22:16:17 +0000 (22:16 +0000)
initializer; all other constexpr variables are merely required to be
initialized. In particular, a user-provided constexpr default constructor can be
used for such initialization.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144028 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 7bfd7fb32ceb351d09c54faf24b479a8f852fef4..e976470b2ce5c411db01fc3454f0b307ba6f9939 100644 (file)
@@ -1250,8 +1250,8 @@ 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_static_mem_var_requires_init : Error<
+  "declaration of constexpr static data member %0 requires an initializer">;
 def err_constexpr_var_requires_const_init : Error<
   "constexpr variable %0 must be initialized by a constant expression">;
 def err_constexpr_redecl_mismatch : Error<
index d71cd5f7d5441e5103fb87afdf8190b70f66334a..8419cbebc4bc890e6d980662bf77d5f7acedc013 100644 (file)
@@ -6191,17 +6191,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
   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.
   VDecl->setInit(Init);
@@ -6266,16 +6255,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
       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.
-    //
-    // A static data member's definition may inherit an initializer from an
-    // in-class declaration.
-    if (Var->isConstexpr() && !Var->getAnyInitializer()) {
-      Diag(Var->getLocation(), diag::err_constexpr_var_requires_init)
+    if (Var->isConstexpr() && Var->isStaticDataMember() &&
+        !Var->isThisDeclarationADefinition()) {
+      Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init)
         << Var->getDeclName();
       Var->setInvalidDecl();
       return;
@@ -6533,15 +6518,21 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
     }
   }
 
-  // Check for global constructors.
+  Expr *Init = var->getInit();
+  bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal();
+
   if (!var->getDeclContext()->isDependentContext() &&
-      var->hasGlobalStorage() &&
-      !var->isStaticLocal() &&
-      var->getInit() &&
-      !var->getInit()->isConstantInitializer(Context,
-                                             baseType->isReferenceType()))
-    Diag(var->getLocation(), diag::warn_global_constructor)
-      << var->getInit()->getSourceRange();
+      (var->isConstexpr() || IsGlobal) && Init &&
+      !Init->isConstantInitializer(Context, baseType->isReferenceType())) {
+    // FIXME: Improve this diagnostic to explain why the initializer is not
+    // a constant expression.
+    if (var->isConstexpr())
+      Diag(var->getLocation(), diag::err_constexpr_var_requires_const_init)
+        << var << Init->getSourceRange();
+    if (IsGlobal)
+      Diag(var->getLocation(), diag::warn_global_constructor)
+        << Init->getSourceRange();
+  }
 
   // Require the destructor.
   if (const RecordType *recordType = baseType->getAs<RecordType>())
index a4e25231a73e5ce3339d3dbca6244057d1f3f198..db2dd22e68cefd9a302428f4a11948924cb154ce 100644 (file)
@@ -8972,16 +8972,6 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
   
   Expr *Init = Result.get();
   CheckImplicitConversions(Init, LParenLoc);
-  
-  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);
index 007e416e6a492f4685dc7dea48229f80de796656..77870f42559887d0dd2751e58fd024b85767f80f 100644 (file)
@@ -6,7 +6,7 @@ struct 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 b; // expected-error {{declaration of constexpr static data member 'b' requires an initializer}}
 
   static constexpr int c = 0;
   static const int d;
index bd7a5f33fd38c6caa8ab07dc716b1de82a40d492..426756ad97233af2c3bee8477e7c4142043e3200 100644 (file)
@@ -20,7 +20,7 @@ constexpr int s1::mi2 = 0;
 // not a definition of an object
 constexpr extern int i2; // expected-error {{constexpr variable declaration must be a definition}}
 // not a literal type
-constexpr notlit nl1; // expected-error {{declaration of constexpr variable 'nl1' requires an initializer}}
+constexpr notlit nl1; // expected-error {{constexpr variable 'nl1' must be initialized by a constant expression}}
 // function parameters
 void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}
 // non-static member
index 53d232d8a90ad5842b5afcc2c1020423825b6a8f..fe79a0e6fc1dfa192453f1f0f92ad62c21b42aee 100644 (file)
@@ -17,9 +17,9 @@ 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 ni1; // expected-error {{default initialization of an object of const type 'const int'}}
+constexpr struct C { C(); } ni2; // expected-error {{constexpr variable 'ni2' must be initialized by a constant expression}}
+constexpr double &ni3; // expected-error {{declaration of reference 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}}
@@ -34,4 +34,4 @@ struct pixel {
   int x, y;
 };
 constexpr pixel ur = { 1294, 1024 }; // ok
-constexpr pixel origin;              // expected-error {{requires an initializer}}
+constexpr pixel origin;              // expected-error {{default initialization of an object of const type 'const pixel' requires a user-provided default constructor}}