constexpr: static data members declared constexpr are required to have an
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
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 7bfd7fb..e976470 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1250,8 +1250,8 @@
"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<
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d71cd5f..8419cbe 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -6191,17 +6191,6 @@
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 @@
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 @@
}
}
- // 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>())
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a4e2523..db2dd22 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -8972,16 +8972,6 @@
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);
diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp
index 007e416..77870f4 100644
--- a/test/CXX/class/class.static/class.static.data/p3.cpp
+++ b/test/CXX/class/class.static/class.static.data/p3.cpp
@@ -6,7 +6,7 @@
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;
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 bd7a5f3..426756a 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -20,7 +20,7 @@
// 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
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
index 53d232d..fe79a0e 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp
@@ -17,9 +17,9 @@
// 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 @@
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}}