diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index f672433c89..2caba65d78 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -92,6 +92,53 @@ namespace llvm { namespace clang { +/// AccessSpecDecl - An access specifier followed by colon ':'. +/// +/// An objects of this class represents sugar for the syntactic occurrence +/// of an access specifier followed by a colon in the list of member +/// specifiers of a C++ class definition. +/// +/// Note that they do not represent other uses of access specifiers, +/// such as those occurring in a list of base specifiers. +/// Also note that this class has nothing to do with so-called +/// "access declarations" (C++98 11.3 [class.access.dcl]). +class AccessSpecDecl : public Decl { + /// ColonLoc - The location of the ':'. + SourceLocation ColonLoc; + + AccessSpecDecl(AccessSpecifier AS, DeclContext *DC, + SourceLocation ASLoc, SourceLocation ColonLoc) + : Decl(AccessSpec, DC, ASLoc), ColonLoc(ColonLoc) { + setAccess(AS); + } +public: + /// getAccessSpecifierLoc - The location of the access specifier. + SourceLocation getAccessSpecifierLoc() const { return getLocation(); } + /// setAccessSpecifierLoc - Sets the location of the access specifier. + void setAccessSpecifierLoc(SourceLocation ASLoc) { setLocation(ASLoc); } + + /// getColonLoc - The location of the colon following the access specifier. + SourceLocation getColonLoc() const { return ColonLoc; } + /// setColonLoc - Sets the location of the colon. + void setColonLoc(SourceLocation CLoc) { ColonLoc = CLoc; } + + SourceRange getSourceRange() const { + return SourceRange(getAccessSpecifierLoc(), getColonLoc()); + } + + static AccessSpecDecl *Create(ASTContext &C, AccessSpecifier AS, + DeclContext *DC, SourceLocation ASLoc, + SourceLocation ColonLoc) { + return new (C) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const AccessSpecDecl *D) { return true; } + static bool classofKind(Kind K) { return K == AccessSpec; } +}; + + /// CXXBaseSpecifier - A base class of a C++ class. /// /// Each CXXBaseSpecifier represents a single, direct base class (or diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index 8025394f3c..a25f3ee10b 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -61,6 +61,7 @@ def ObjCPropertyImpl : Decl; def ObjCForwardProtocol : Decl; def ObjCClass : Decl; def FileScopeAsm : Decl; +def AccessSpec : Decl; def Friend : Decl; def FriendTemplate : Decl; def StaticAssert : Decl; diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 2493cfd47d..32643de261 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -562,6 +562,8 @@ namespace clang { DECL_CXX_DESTRUCTOR, /// \brief A CXXConversionDecl record. DECL_CXX_CONVERSION, + /// \brief An AccessSpecDecl record. + DECL_ACCESS_SPEC, // FIXME: Implement serialization for these decl types. This just // allocates the order in which diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 74b3b5b764..0b07ded05d 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1769,6 +1769,15 @@ public: unsigned NumBases) { } + /// ActOnAccessSpecifier - This is invoked when an access specifier + /// (and the colon following it) is found during the parsing of a + /// C++ class member declarator. + virtual DeclPtrTy ActOnAccessSpecifier(AccessSpecifier AS, + SourceLocation ASLoc, + SourceLocation ColonLoc) { + return DeclPtrTy(); + } + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BitfieldWidth' /// specifies the bitfield width if there is one and 'Init' specifies the diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index a73d17a5ca..8f6fdbc956 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -291,6 +291,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { // Never have names. case Friend: case FriendTemplate: + case AccessSpec: case LinkageSpec: case FileScopeAsm: case StaticAssert: diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 5394924797..2fb6cb1d31 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -183,7 +183,7 @@ void DeclPrinter::Print(AccessSpecifier AS) { case AS_none: assert(0 && "No access specifier!"); break; case AS_public: Out << "public"; break; case AS_protected: Out << "protected"; break; - case AS_private: Out << " private"; break; + case AS_private: Out << "private"; break; } } @@ -195,9 +195,6 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { if (Indent) Indentation += Policy.Indentation; - bool PrintAccess = isa(DC); - AccessSpecifier CurAS = AS_none; - llvm::SmallVector Decls; for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) { @@ -211,18 +208,6 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { continue; } - if (PrintAccess) { - AccessSpecifier AS = D->getAccess(); - - if (AS != CurAS) { - if (Indent) - this->Indent(Indentation - Policy.Indentation); - Print(AS); - Out << ":\n"; - CurAS = AS; - } - } - // The next bits of code handles stuff like "struct {int x;} a,b"; we're // forced to merge the declarations because there's no other way to // refer to the struct in question. This limited merging is safe without @@ -251,6 +236,16 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { Decls.push_back(*D); continue; } + + if (isa(*D)) { + Indentation -= Policy.Indentation; + this->Indent(); + Print(D->getAccess()); + Out << ":\n"; + Indentation += Policy.Indentation; + continue; + } + this->Indent(); Visit(*D); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 5b0cc00cd7..e8b67b8864 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -59,6 +59,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::ObjCImplementation: case Decl::ObjCProperty: case Decl::ObjCCompatibleAlias: + case Decl::AccessSpec: case Decl::LinkageSpec: case Decl::ObjCPropertyImpl: case Decl::ObjCClass: diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 5056f93377..7ccf14362f 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -80,6 +80,7 @@ namespace { void VisitUsingShadow(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); + void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *BD); @@ -607,6 +608,11 @@ void PCHDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { VisitCXXMethodDecl(D); } +void PCHDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { + VisitDecl(D); + D->setColonLoc(Reader.ReadSourceLocation(Record, Idx)); +} + void PCHDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { assert(false && "cannot read FriendTemplateDecl"); } @@ -971,6 +977,10 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { case pch::DECL_CXX_CONVERSION: D = CXXConversionDecl::Create(*Context, Decl::EmptyShell()); break; + case pch::DECL_ACCESS_SPEC: + D = AccessSpecDecl::Create(*Context, AS_none, 0, SourceLocation(), + SourceLocation()); + break; case pch::DECL_FRIEND: assert(false && "cannot read FriendDecl"); break; diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 499a16adb1..6b88dfcae4 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -81,6 +81,7 @@ namespace { void VisitUsingShadow(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *D); @@ -607,6 +608,12 @@ void PCHDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { Code = pch::DECL_CXX_CONVERSION; } +void PCHDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) { + VisitDecl(D); + Writer.AddSourceLocation(D->getColonLoc(), Record); + Code = pch::DECL_ACCESS_SPEC; +} + void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) { assert(false && "cannot write FriendTemplateDecl"); } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 7e59170b37..eda490d918 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1570,8 +1570,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (AS != AS_none) { // Current token is a C++ access specifier. CurAS = AS; + SourceLocation ASLoc = Tok.getLocation(); + ConsumeToken(); + if (Tok.is(tok::colon)) + Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation()); + else + Diag(Tok, diag::err_expected_colon); ConsumeToken(); - ExpectAndConsume(tok::colon, diag::err_expected_colon); continue; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 5d4b39e292..064d34316e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2544,6 +2544,10 @@ public: virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS); + virtual DeclPtrTy ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc); + virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 501d878f57..03b2ef5643 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1770,6 +1770,8 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, << (int)Record->isUnion(); Invalid = true; } + } else if (isa(*Mem)) { + // Any access specifier is fine. } else { // We have something that isn't a non-static data // member. Complain about it. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a6a1943ecd..7dcda88407 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -871,6 +871,17 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { // C++ class member Handling //===----------------------------------------------------------------------===// +/// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. +Sema::DeclPtrTy +Sema::ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, SourceLocation ColonLoc) { + assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); + AccessSpecDecl* ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, + ASLoc, ColonLoc); + CurContext->addHiddenDecl(ASDecl); + return DeclPtrTy::make(ASDecl); +} + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one and 'InitExpr' specifies the initializer if diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 939f6caa96..0af3ed9095 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -48,6 +48,7 @@ namespace { Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D); Decl *VisitTypedefDecl(TypedefDecl *D); Decl *VisitVarDecl(VarDecl *D); + Decl *VisitAccessSpecDecl(AccessSpecDecl *D); Decl *VisitFieldDecl(FieldDecl *D); Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitEnumDecl(EnumDecl *D); @@ -437,6 +438,14 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { return Var; } +Decl *TemplateDeclInstantiator::VisitAccessSpecDecl(AccessSpecDecl *D) { + AccessSpecDecl* AD + = AccessSpecDecl::Create(SemaRef.Context, D->getAccess(), Owner, + D->getAccessSpecifierLoc(), D->getColonLoc()); + Owner->addHiddenDecl(AD); + return AD; +} + Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 903d341a79..6410d3715f 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2041,6 +2041,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::TemplateTemplateParm: case Decl::ObjCCategoryImpl: case Decl::ObjCImplementation: + case Decl::AccessSpec: case Decl::LinkageSpec: case Decl::ObjCPropertyImpl: case Decl::FileScopeAsm: