From eda3c8469827faff11f3ab423492c3bc7e27ea0c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 7 Nov 2011 22:16:17 +0000 Subject: [PATCH] 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. llvm-svn: 144028 --- .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/lib/Sema/SemaDecl.cpp | 43 ++++++++----------- clang/lib/Sema/SemaDeclCXX.cpp | 10 ----- .../class.static/class.static.data/p3.cpp | 2 +- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp | 2 +- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp | 8 ++-- 6 files changed, 25 insertions(+), 44 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7bfd7fb32ceb..e976470b2ce5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d71cd5f7d544..8419cbebc4bc 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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()) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a4e25231a73e..db2dd22e68ce 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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); diff --git a/clang/test/CXX/class/class.static/class.static.data/p3.cpp b/clang/test/CXX/class/class.static/class.static.data/p3.cpp index 007e416e6a49..77870f425598 100644 --- a/clang/test/CXX/class/class.static/class.static.data/p3.cpp +++ b/clang/test/CXX/class/class.static/class.static.data/p3.cpp @@ -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; diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp index bd7a5f33fd38..426756ad9723 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp @@ -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 diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp index 53d232d8a90a..fe79a0e6fc1d 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp @@ -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}}