]> granicus.if.org Git - clang/commitdiff
Implement parsing and semantic checking of the 'mutable' keyword.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 14 Nov 2008 23:42:31 +0000 (23:42 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Fri, 14 Nov 2008 23:42:31 +0000 (23:42 +0000)
Thanks to Doug for the review. Actual effects of mutable to follow.

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

include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/DeclSpec.h
lib/Parse/DeclSpec.cpp
lib/Parse/ParseDecl.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/Parser/cxx-class.cpp
test/SemaCXX/class.cpp
www/cxx_status.html

index 9073e26c98f26efb19382f27883df685907d574d..b7b1b6e6ded2d8d6145f67b78cecdd08dd0820f8 100644 (file)
@@ -669,6 +669,14 @@ DIAG(err_bad_language, ERROR,
 // C++ class members
 DIAG(err_storageclass_invalid_for_member, ERROR,
      "storage class specified for a member declaration")
+DIAG(err_mutable_function, ERROR,
+     "'mutable' cannot be applied to functions")
+DIAG(err_mutable_reference, ERROR,
+     "'mutable' cannot be applied to references")
+DIAG(err_mutable_const, ERROR,
+     "'mutable' and 'const' cannot be mixed")
+DIAG(err_mutable_nonmember, ERROR,
+     "'mutable' can only be applied to member variables")
 DIAG(err_virtual_non_function, ERROR,
      "'virtual' can only appear on non-static member functions")
 DIAG(err_not_bitfield_type, ERROR,
index 94bd839a014113bd33553749bb718d19ecbb5f14..d1b887ff3028760baf14480d3e571d9853cd35c3 100644 (file)
@@ -36,7 +36,8 @@ public:
     SCS_static,
     SCS_auto,
     SCS_register,
-    SCS_private_extern
+    SCS_private_extern,
+    SCS_mutable
   };
   
   // type-specifier
index d61d6c5d6c25d3ffa3ff69f22120980e8ccb0120..e80076127d847696acc8481c5f24185299e81470 100644 (file)
@@ -44,6 +44,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) {
   case DeclSpec::SCS_static:      return "static";
   case DeclSpec::SCS_auto:        return "auto";
   case DeclSpec::SCS_register:    return "register";
+  case DeclSpec::SCS_mutable:     return "mutable";
   }
 }
 
@@ -126,6 +127,7 @@ bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
     return BadSpecifier( (SCS)StorageClassSpec, PrevSpec);
   StorageClassSpec = S;
   StorageClassSpecLoc = Loc;
+  assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
   return false;
 }
 
index 0c1080a5b8ff381e7ff882c07c2b9c3d4970546a..99bebe62585bc0550c89cd7cc70894212e9a4b21 100644 (file)
@@ -405,6 +405,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) {
 ///         'static'
 ///         'auto'
 ///         'register'
+/// [C++]   'mutable'
 /// [GNU]   '__thread'
 ///       function-specifier: [C99 6.7.4]
 /// [C99]   'inline'
@@ -550,6 +551,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
     case tok::kw_register:
       isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_register, Loc, PrevSpec);
       break;
+    case tok::kw_mutable:
+      isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_mutable, Loc, PrevSpec);
+      break;
     case tok::kw___thread:
       isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
       break;
index 76835bc3abcce027428da3aedd7f77688fac72a2..dd76e15c09bb3ef5e80f3aab7b906dacc0696f63 100644 (file)
@@ -853,6 +853,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
       default: assert(0 && "Unknown storage class!");
       case DeclSpec::SCS_auto:        
       case DeclSpec::SCS_register:
+      case DeclSpec::SCS_mutable:
         Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func,
              R.getAsString());
         InvalidDecl = true;
@@ -1103,7 +1104,12 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
     case DeclSpec::SCS_auto:           SC = VarDecl::Auto; break;
     case DeclSpec::SCS_register:       SC = VarDecl::Register; break;
     case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break;
-    }    
+    case DeclSpec::SCS_mutable:
+      // mutable can only appear on non-static class members, so it's always
+      // an error here
+      Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember);
+      InvalidDecl = true;
+    }
     if (DC->isCXXRecord()) {
       assert(SC == VarDecl::Static && "Invalid storage class for member!");
       // This is a static data member for a C++ class.
@@ -1121,11 +1127,11 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
           InvalidDecl = true;
         }
       }
-        NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), 
-                                II, R, SC, LastDeclarator,
-                                // FIXME: Move to DeclGroup...
-                                D.getDeclSpec().getSourceRange().getBegin());
-        NewVD->setThreadSpecified(ThreadSpecified);
+      NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), 
+                              II, R, SC, LastDeclarator,
+                              // FIXME: Move to DeclGroup...
+                              D.getDeclSpec().getSourceRange().getBegin());
+      NewVD->setThreadSpecified(ThreadSpecified);
     }
     // Handle attributes prior to checking for duplicates in MergeVarDecl
     ProcessDeclAttributes(NewVD, D);
index 9bf10cece810dca8679dd9ad582688d37a1e2cec..f8369b3d8da2d2580e6a61e40183d7969ca4a8e9 100644 (file)
@@ -425,14 +425,44 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
   Expr *Init = static_cast<Expr*>(InitExpr);
   SourceLocation Loc = D.getIdentifierLoc();
 
+  bool isFunc = D.isFunctionDeclarator();
+
   // C++ 9.2p6: A member shall not be declared to have automatic storage
   // duration (auto, register) or with the extern storage-class-specifier.
+  // C++ 7.1.1p8: The mutable specifier can be applied only to names of class
+  // data members and cannot be applied to names declared const or static,
+  // and cannot be applied to reference members.
   switch (DS.getStorageClassSpec()) {
     case DeclSpec::SCS_unspecified:
     case DeclSpec::SCS_typedef:
     case DeclSpec::SCS_static:
       // FALL THROUGH.
       break;
+    case DeclSpec::SCS_mutable:
+      if (isFunc) {
+        if (DS.getStorageClassSpecLoc().isValid())
+          Diag(DS.getStorageClassSpecLoc(),
+               diag::err_mutable_function);
+        else
+          Diag(DS.getThreadSpecLoc(),
+               diag::err_mutable_function);
+        D.getMutableDeclSpec().ClearStorageClassSpecs();
+      } else {
+        QualType T = GetTypeForDeclarator(D, S);
+        diag::kind err = static_cast<diag::kind>(0);
+        if (T->isReferenceType())
+          err = diag::err_mutable_reference;
+        else if (T.isConstQualified())
+          err = diag::err_mutable_const;
+        if (err != 0) {
+          if (DS.getStorageClassSpecLoc().isValid())
+            Diag(DS.getStorageClassSpecLoc(), err);
+          else
+            Diag(DS.getThreadSpecLoc(), err);
+          D.getMutableDeclSpec().ClearStorageClassSpecs();
+        }
+      }
+      break;
     default:
       if (DS.getStorageClassSpecLoc().isValid())
         Diag(DS.getStorageClassSpecLoc(),
@@ -442,7 +472,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
       D.getMutableDeclSpec().ClearStorageClassSpecs();
   }
 
-  bool isFunc = D.isFunctionDeclarator();
   if (!isFunc &&
       D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_typedef &&
       D.getNumTypeObjects() == 0) {
@@ -455,7 +484,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
     isFunc = Context.getTypeDeclType(cast<TypeDecl>(TD))->isFunctionType();
   }
 
-  bool isInstField = (DS.getStorageClassSpec() == DeclSpec::SCS_unspecified &&
+  bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified ||
+                       DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
                       !isFunc);
 
   Decl *Member;
index ef0c901dfa5847e172b1dd981a3578b6d6230d1b..5afa8d6ac23977e5ea42db1e7de6eb0c4286988e 100644 (file)
@@ -21,6 +21,7 @@ private:
   int x,f(),y,g();
   inline int h();
   static const int sci = 10;
+  mutable int mi;
 };
 void glo()
 {
index 7eeecdc5770e156e6887d115bbd18735790d9b9c..ada508ac3225fe648b1aa3ace4cf6ff941c13ed4 100644 (file)
@@ -61,6 +61,11 @@ private:
   int x,y;
   static int sx;
 
+  mutable int mi;
+  mutable int &mir; // expected-error {{error: 'mutable' cannot be applied to references}}
+  mutable void mfn(); // expected-error {{error: 'mutable' cannot be applied to functions}}
+  mutable const int mci; // expected-error {{error: 'mutable' and 'const' cannot be mixed}}
+
   static const int number = 50;
   static int arr[number];
 };
@@ -76,3 +81,11 @@ class C2 {
     };
   }
 };
+
+// Play with mutable a bit more, to make sure it doesn't crash anything.
+mutable int gi; // expected-error {{error: 'mutable' can only be applied to member variables}}
+mutable void gfn(); // expected-error {{illegal storage class on function}}
+void ogfn()
+{
+  mutable int ml; // expected-error {{error: 'mutable' can only be applied to member variables}}
+}
index f4e3402584d455f50aa6598a6cca9603368af13c..c8b8d57ef0cf5737b67c8afa6c380ca404dd6cea 100644 (file)
@@ -607,7 +607,7 @@ welcome!</p>
   <td></td>\r
   <td></td>\r
   <td></td>\r
-  <td>No parser support for mutable members, using declarations, or templates.</td>\r
+  <td>No parser support for using declarations, or templates.</td>\r
 </tr>\r
 <tr>\r
   <td>&nbsp;&nbsp;9.3 [class.mfct]</td>\r