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]