]> granicus.if.org Git - clang/commitdiff
Provide a fixit for constexpr non-static data members.
authorDavid Blaikie <dblaikie@gmail.com>
Wed, 30 Jan 2013 01:22:18 +0000 (01:22 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Wed, 30 Jan 2013 01:22:18 +0000 (01:22 +0000)
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))

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173873 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
test/FixIt/fixit-cxx0x.cpp

index 326b96e626c586d00504330993e1208fc46ce6df..a3b03033d23e7f80b1f1f6ed9cd7a6b7d88dd03c 100644 (file)
@@ -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">;
index 5af3ea741a1c7d8b9a5f68a34e5b5f1e80faac09..4956c1095c3f7168e1da81a059aab0134bc35abd 100644 (file)
@@ -2165,8 +2165,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
       } else {
         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 :
index 60b67602c3f010eb5aee3c8792a964f85cd6dcea..2c09c88b2010a575cfaf730a5a09cfdc88c7fc4a 100644 (file)
@@ -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;
index 448d083aaf2a84085eb14937174af76e1a96dd8b..59d1e91f367a3b04649117209145a7c8643a4ecb 100644 (file)
@@ -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) {
index 6820fc6cb8796748007315f242ff4b710c681a68..2a12f92a8de7198594f54caab9e1588bfc0d75d1 100644 (file)
@@ -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}}
index a173ce4bc271581607340100b29a456e0d5a8611..3884c64516b597dfd45e0ffceb2315f429fc4b64 100644 (file)
@@ -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;
+    }
+  };
+}