diff options
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 52 | ||||
-rw-r--r-- | test/FixIt/fixit-cxx0x.cpp | 35 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 10 |
3 files changed, 24 insertions, 73 deletions
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<VarDecl>(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}} + } +} |