From: Richard Smith Date: Sun, 25 Dec 2011 21:17:58 +0000 (+0000) Subject: Fix constexpr handling to allow 'extern constexpr' variable declarations. We no X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dd4b350143c26c030a482f091908a2e077503411;p=clang Fix constexpr handling to allow 'extern constexpr' variable declarations. We no longer have access to the source locations we need to produce the 'replace constexpr with const' fixits, so they're gone for now. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147273 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d9d7f0a99d..00c6b9fcf0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3948,38 +3948,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateParamLists.release()); } - if (D.getDeclSpec().isConstexprSpecified()) { - // 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); - } - } + if (D.getDeclSpec().isConstexprSpecified()) + NewVD->setConstexpr(true); } // Set the lexical context. If the declarator has a C++ scope specifier, the @@ -6244,7 +6214,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, if (VarDecl *Var = dyn_cast(RealDecl)) { QualType Type = Var->getType(); - // C++0x [dcl.spec.auto]p3 + // C++11 [dcl.spec.auto]p3 if (TypeMayContainAuto && Type->getContainedAutoType()) { Diag(Var->getLocation(), diag::err_auto_var_requires_init) << Var->getDeclName() << Type; @@ -6252,13 +6222,19 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, return; } - // C++0x [class.static.data]p3: A static data member can be declared with + // C++11 [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() && Var->isStaticDataMember() && - !Var->isThisDeclarationADefinition()) { - Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init) - << Var->getDeclName(); + // C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to + // the definition of a variable [...] or the declaration of a static data + // member. + if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) { + if (Var->isStaticDataMember()) + Diag(Var->getLocation(), + diag::err_constexpr_static_mem_var_requires_init) + << Var->getDeclName(); + else + Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl); Var->setInvalidDecl(); return; } diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp index 9fb647d03f..b2b69b6f4b 100644 --- a/test/FixIt/fixit-cxx0x.cpp +++ b/test/FixIt/fixit-cxx0x.cpp @@ -18,41 +18,6 @@ using ::T = void; // expected-error {{name defined in alias declaration must be 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 b; // xpected-error {{requires an initializer}} - // -> const int b; - }; - - constexpr int S::b = 0; -#endif - - struct S { - static char *const p = 0; // expected-error {{requires 'constexpr' specifier}} - // -> constexpr static char *const p = 0; - }; -} - namespace SemiCommaTypo { int m {}, n [[]], // expected-error {{expected ';' at end of declaration}} diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 0993a982d8..d78c16cca6 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -961,3 +961,13 @@ struct S { }; } + +namespace ExternConstexpr { + extern constexpr int n = 0; + extern constexpr int m; // expected-error {{constexpr variable declaration must be a definition}} + void f() { + extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}} + constexpr int j = 0; + constexpr int k; // expected-error {{default initialization of an object of const type}} + } +}