summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Blaikie <dblaikie@gmail.com>2013-01-30 01:22:18 +0000
committerDavid Blaikie <dblaikie@gmail.com>2013-01-30 01:22:18 +0000
commit35506f82025c7dd0980d7553e6f9b6df2a4d2b30 (patch)
tree10a15b72e8d9559dd66c50e63c8131b4b8ce870a
parent4d365ba9b972b14a182976476fdbfb374721bd9c (diff)
downloadbcm5719-llvm-35506f82025c7dd0980d7553e6f9b6df2a4d2b30.tar.gz
bcm5719-llvm-35506f82025c7dd0980d7553e6f9b6df2a4d2b30.zip
Provide a fixit for constexpr non-static data members.
If the member has an initializer, assume it was probably intended to be static and suggest/recover with that. If the member doesn't have an initializer, assume it was probably intended to be const instead of constexpr and suggest that. (if the attempt to apply these changes fails, don't make any suggestion & produce the same diagnostic experience as before. The only case where this can come up that I know of is with a mutable constexpr with an initializer, since mutable is incompatible with static (but it's already incompatible with const anyway)) llvm-svn: 173873
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp6
-rw-r--r--clang/lib/Sema/SemaDecl.cpp3
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp31
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp4
-rw-r--r--clang/test/FixIt/fixit-cxx0x.cpp12
6 files changed, 50 insertions, 8 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 326b96e626c..a3b03033d23 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1536,6 +1536,8 @@ def warn_cxx98_compat_constexpr : Warning<
def err_invalid_constexpr : Error<
"%select{function parameter|typedef|non-static data member}0 "
"cannot be constexpr">;
+def err_invalid_constexpr_member : Error<"non-static data member cannot be "
+ "constexpr%select{; did you intend to make it %select{const|static}0?|}1">;
def err_constexpr_tag : Error<
"%select{class|struct|interface|union|enum}0 cannot be marked constexpr">;
def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 5af3ea741a1..4956c1095c3 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2166,8 +2166,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
HasInitializer = true;
if (!DeclaratorInfo.isDeclarationOfFunction() &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_static &&
- DeclaratorInfo.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_typedef)
HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit;
}
@@ -2218,7 +2216,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
LateParsedAttrs.clear();
// Handle the initializer.
- if (HasInClassInit != ICIS_NoInit) {
+ if (HasInClassInit != ICIS_NoInit &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
+ DeclSpec::SCS_static) {
// The initializer was deferred; parse it and cache the tokens.
Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_nonstatic_member_init :
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 60b67602c3f..2c09c88b201 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9927,9 +9927,6 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- if (D.getDeclSpec().isConstexprSpecified())
- Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 2;
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = 0;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 448d083aaf2..59d1e91f367 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1666,6 +1666,35 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
!isFunc);
+ if (DS.isConstexprSpecified() && isInstField) {
+ SemaDiagnosticBuilder B =
+ Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr_member);
+ SourceLocation ConstexprLoc = DS.getConstexprSpecLoc();
+ if (InitStyle == ICIS_NoInit) {
+ B << 0 << 0 << FixItHint::CreateReplacement(ConstexprLoc, "const");
+ D.getMutableDeclSpec().ClearConstexprSpec();
+ const char *PrevSpec;
+ unsigned DiagID;
+ bool Failed = D.getMutableDeclSpec().SetTypeQual(DeclSpec::TQ_const, ConstexprLoc,
+ PrevSpec, DiagID, getLangOpts());
+ assert(!Failed && "Making a constexpr member const shouldn't fail");
+ } else {
+ B << 1;
+ const char *PrevSpec;
+ unsigned DiagID;
+ DeclSpec::SCS PrevSCS = DS.getStorageClassSpec();
+ if (D.getMutableDeclSpec().SetStorageClassSpec(
+ *this, DeclSpec::SCS_static, ConstexprLoc, PrevSpec, DiagID)) {
+ assert(PrevSCS == DeclSpec::SCS_mutable &&
+ "This is the only DeclSpec that should fail to be applied");
+ B << 1;
+ } else {
+ B << 0 << FixItHint::CreateInsertion(ConstexprLoc, "static ");
+ isInstField = false;
+ }
+ }
+ }
+
NamedDecl *Member;
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
@@ -1720,7 +1749,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
InitStyle, AS);
assert(Member && "HandleField never returns null");
} else {
- assert(InitStyle == ICIS_NoInit);
+ assert(InitStyle == ICIS_NoInit || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static);
Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member) {
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 6820fc6cb87..2a12f92a8de 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
@@ -25,8 +25,10 @@ constexpr notlit nl1; // expected-error {{constexpr variable cannot have non-lit
void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}
// non-static member
struct s2 {
- constexpr int mi1; // expected-error {{non-static data member cannot be constexpr}}
+ constexpr int mi1; // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
static constexpr int mi2; // expected-error {{requires an initializer}}
+ // FIXME: verify that there's no extra suffix in this error. -verify doesn't support anything like that at the moment as far as I know
+ mutable constexpr int mi3; // expected-error {{non-static data member cannot be constexpr}} expected-error {{'mutable' and 'const' cannot be mixed}}
};
// typedef
typedef constexpr int CI; // expected-error {{typedef cannot be constexpr}}
diff --git a/clang/test/FixIt/fixit-cxx0x.cpp b/clang/test/FixIt/fixit-cxx0x.cpp
index a173ce4bc27..3884c64516b 100644
--- a/clang/test/FixIt/fixit-cxx0x.cpp
+++ b/clang/test/FixIt/fixit-cxx0x.cpp
@@ -120,3 +120,15 @@ namespace MissingSemi {
struct d // expected-error {{expected ';' after struct}}
}
}
+
+namespace NonStaticConstexpr {
+ struct foo {
+ constexpr int i; // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
+ constexpr int j = 7; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
+ foo() : i(3) {
+ }
+ static int get_j() {
+ return j;
+ }
+ };
+}
OpenPOWER on IntegriCloud