From: Sebastian Redl
Date: Fri, 14 Nov 2008 23:42:31 +0000 (+0000)
Subject: Implement parsing and semantic checking of the 'mutable' keyword.
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=669d5d74b880a8497b92a3ec159145713f4d6519;p=clang
Implement parsing and semantic checking of the 'mutable' keyword.
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
---
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 9073e26c98..b7b1b6e6de 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -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,
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index 94bd839a01..d1b887ff30 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -36,7 +36,8 @@ public:
SCS_static,
SCS_auto,
SCS_register,
- SCS_private_extern
+ SCS_private_extern,
+ SCS_mutable
};
// type-specifier
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index d61d6c5d6c..e80076127d 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -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;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0c1080a5b8..99bebe6258 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 76835bc3ab..dd76e15c09 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9bf10cece8..f8369b3d8d 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -425,14 +425,44 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Expr *Init = static_cast(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(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(TD))->isFunctionType();
}
- bool isInstField = (DS.getStorageClassSpec() == DeclSpec::SCS_unspecified &&
+ bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified ||
+ DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
!isFunc);
Decl *Member;
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index ef0c901dfa..5afa8d6ac2 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -21,6 +21,7 @@ private:
int x,f(),y,g();
inline int h();
static const int sci = 10;
+ mutable int mi;
};
void glo()
{
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 7eeecdc577..ada508ac32 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -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}}
+}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index f4e3402584..c8b8d57ef0 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -607,7 +607,7 @@ welcome!
|
|
|
- No parser support for mutable members, using declarations, or templates. |
+ No parser support for using declarations, or templates. |
9.3 [class.mfct] |