diff options
-rw-r--r-- | include/clang-c/Index.h | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 18 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 9 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 25 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 9 | ||||
-rw-r--r-- | test/Index/annotate-attribute.cpp | 33 | ||||
-rw-r--r-- | test/Parser/access-spec-attrs.cpp | 12 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 7 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 1 |
13 files changed, 131 insertions, 27 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 9ff04f4eb2..3df1670f10 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -1830,7 +1830,8 @@ enum CXCursorKind { CXCursor_IBOutletCollectionAttr = 403, CXCursor_CXXFinalAttr = 404, CXCursor_CXXOverrideAttr = 405, - CXCursor_LastAttr = CXCursor_CXXOverrideAttr, + CXCursor_AnnotateAttr = 406, + CXCursor_LastAttr = CXCursor_AnnotateAttr, /* Preprocessing */ CXCursor_PreprocessingDirective = 500, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 38b34a46ca..36386ec726 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1365,6 +1365,8 @@ def err_attr_objc_ownership_redundant : Error< "the type %0 already has retainment attributes set on it">; def err_attribute_not_string : Error< "argument to %0 attribute was not a string literal">; +def err_only_annotate_after_access_spec : Error< + "access specifier can only have annotation attributes">; def err_attribute_section_invalid_for_target : Error< "argument to 'section' attribute is not valid for this target: %0">; def err_attribute_section_local_variable : Error< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index eed8862159..0046f88d26 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1125,7 +1125,8 @@ private: void DeallocateParsedClasses(ParsingClass *Class); void PopParsingClass(Sema::ParsingClassState); - Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, + Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs, + ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, const VirtSpecifiers& VS, ExprResult& Init); void ParseCXXNonStaticMemberInitializer(Decl *VarD); @@ -1961,7 +1962,7 @@ private: Decl *TagDecl); ExprResult ParseCXXMemberInitializer(bool IsFunction, SourceLocation &EqualLoc); - void ParseCXXClassMemberDeclaration(AccessSpecifier AS, + void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), ParsingDeclRAIIObject *DiagsFromTParams = 0); void ParseConstructorInitializer(Decl *ConstructorDecl); @@ -1997,17 +1998,20 @@ private: // C++ 14.1: Template Parameters [temp.param] Decl *ParseDeclarationStartingWithTemplate(unsigned Context, - SourceLocation &DeclEnd, - AccessSpecifier AS = AS_none); + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none, + AttributeList *AccessAttrs = 0); Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context, - SourceLocation &DeclEnd, - AccessSpecifier AS); + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs); Decl *ParseSingleDeclarationAfterTemplate( unsigned Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, - AccessSpecifier AS=AS_none); + AccessSpecifier AS=AS_none, + AttributeList *AccessAttrs = 0); bool ParseTemplateParameters(unsigned Depth, SmallVectorImpl<Decl*> &TemplateParams, SourceLocation &LAngleLoc, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 32bdc73d04..f4b4c70a4d 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1838,6 +1838,8 @@ public: bool NonInheritable = true, bool Inheritable = true); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, bool NonInheritable = true, bool Inheritable = true); + bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, + const AttributeList *AttrList); void checkUnusedDeclAttributes(Declarator &D); @@ -3414,9 +3416,10 @@ public: bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = 0); - Decl *ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, - SourceLocation ColonLoc); + bool ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc, + AttributeList *Attrs = 0); Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 35c181c94f..b387e9e551 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -21,7 +21,9 @@ using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. -Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, +Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, + AttributeList *AccessAttrs, + ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo, const VirtSpecifiers& VS, ExprResult& Init) { assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); @@ -43,6 +45,8 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, move(TemplateParams), 0, VS, /*HasInit=*/false); if (FnD) { + Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, + false, true); bool TypeSpecContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; if (Init.get()) diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index decb7f9ec5..607cb88260 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1577,6 +1577,7 @@ bool Parser::isCXX0XFinalKeyword() const { /// '=' constant-expression /// void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, + AttributeList *AccessAttrs, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { if (Tok.is(tok::at)) { @@ -1643,7 +1644,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, "Nested template improperly parsed?"); SourceLocation DeclEnd; ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, - AS); + AS, AccessAttrs); return; } @@ -1652,7 +1653,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseCXXClassMemberDeclaration(AS, TemplateInfo, TemplateDiags); + return ParseCXXClassMemberDeclaration(AS, AccessAttrs, + TemplateInfo, TemplateDiags); } // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it @@ -1783,7 +1785,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } Decl *FunDecl = - ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init); + ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, + VS, Init); for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) { LateParsedAttrs[i]->setDecl(FunDecl); @@ -1867,6 +1870,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, move(TemplateParams), BitfieldSize.release(), VS, HasDeferredInitializer); + if (AccessAttrs) + Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, + false, true); } // Set the Decl for any late parsed attributes @@ -2109,6 +2115,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, CurAS = AS_private; else CurAS = AS_public; + ParsedAttributes AccessAttrs(AttrFactory); if (TagDecl) { // While we still have something to read, read the member-declarations. @@ -2137,9 +2144,17 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation ASLoc = Tok.getLocation(); unsigned TokLength = Tok.getLength(); ConsumeToken(); + AccessAttrs.clear(); + MaybeParseGNUAttributes(AccessAttrs); + SourceLocation EndLoc; if (Tok.is(tok::colon)) { EndLoc = Tok.getLocation(); + if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, + AccessAttrs.getList())) { + // found another attribute than only annotations + AccessAttrs.clear(); + } ConsumeToken(); } else if (Tok.is(tok::semi)) { EndLoc = Tok.getLocation(); @@ -2158,7 +2173,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // FIXME: Make sure we don't have a template here. // Parse all the comma separated declarators. - ParseCXXClassMemberDeclaration(CurAS); + ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList()); } T.consumeClose(); @@ -2779,7 +2794,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, } // Parse all the comma separated declarators. - ParseCXXClassMemberDeclaration(CurAS); + ParseCXXClassMemberDeclaration(CurAS, 0); } if (Tok.isNot(tok::r_brace)) { diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 4509662c65..92fe4a5f33 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -26,14 +26,16 @@ using namespace clang; Decl * Parser::ParseDeclarationStartingWithTemplate(unsigned Context, SourceLocation &DeclEnd, - AccessSpecifier AS) { + AccessSpecifier AS, + AttributeList *AccessAttrs) { ObjCDeclContextSwitch ObjCDC(*this); if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(), DeclEnd); } - return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS); + return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS, + AccessAttrs); } /// \brief RAII class that manages the template parameter depth. @@ -77,7 +79,8 @@ namespace { Decl * Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, SourceLocation &DeclEnd, - AccessSpecifier AS) { + AccessSpecifier AS, + AttributeList *AccessAttrs) { assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && "Token does not start a template declaration."); @@ -161,7 +164,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, isSpecialization, LastParamListWasEmpty), ParsingTemplateParams, - DeclEnd, AS); + DeclEnd, AS, AccessAttrs); } /// \brief Parse a single declaration that declares a template, @@ -190,13 +193,15 @@ Parser::ParseSingleDeclarationAfterTemplate( const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd, - AccessSpecifier AS) { + AccessSpecifier AS, + AttributeList *AccessAttrs) { assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && "Template information required"); if (Context == Declarator::MemberContext) { // We are parsing a member template. - ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams); + ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo, + &DiagsFromTParams); return 0; } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index f76bb5879a..69baf79ad0 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3743,6 +3743,22 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } +// Annotation attributes are the only attributes allowed after an access +// specifier. +bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, + const AttributeList *AttrList) { + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + if (l->getKind() == AttributeList::AT_annotate) { + handleAnnotateAttr(*this, ASDecl, *l); + } else { + Diag(l->getLoc(), diag::err_only_annotate_after_access_spec); + return true; + } + } + + return false; +} + /// checkUnusedDeclAttributes - Check a list of attributes to see if it /// contains any decl attributes that we should warn about. static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 32da8cbb10..a39584a107 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1376,14 +1376,15 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { //===----------------------------------------------------------------------===// /// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. -Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, - SourceLocation ColonLoc) { +bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc, + AttributeList *Attrs) { assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, ASLoc, ColonLoc); CurContext->addHiddenDecl(ASDecl); - return ASDecl; + return ProcessAccessDeclAttributeList(ASDecl, Attrs); } /// CheckOverrideControl - Check C++0x override control semantics. diff --git a/test/Index/annotate-attribute.cpp b/test/Index/annotate-attribute.cpp new file mode 100644 index 0000000000..6721371ca7 --- /dev/null +++ b/test/Index/annotate-attribute.cpp @@ -0,0 +1,33 @@ +// RUN: c-index-test -test-load-source all %s | FileCheck %s + +class Test { +public: + __attribute__((annotate("spiffy_method"))) void aMethod(); + +public __attribute__((annotate("works"))): + void anotherMethod(); // annotation attribute should be propagated. + +private __attribute__((annotate("investigations"))): + //propagated annotation should have changed from "works" to "investigations" + void inlineMethod() {} + +protected: + // attribute propagation should have stopped here + void methodWithoutAttribute(); +}; + +// CHECK: ClassDecl=Test:3:7 (Definition) Extent=[3:1 - 17:2] +// CHECK: CXXAccessSpecifier=:4:1 (Definition) Extent=[4:1 - 4:8] +// CHECK: CXXMethod=aMethod:5:51 Extent=[5:3 - 5:60] +// CHECK: attribute(annotate)=spiffy_method Extent=[5:18 - 5:43] +// CHECK: CXXAccessSpecifier=:7:1 (Definition) Extent=[7:1 - 7:43] +// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40] +// CHECK: CXXMethod=anotherMethod:8:8 Extent=[8:3 - 8:23] +// CHECK: attribute(annotate)=works Extent=[7:23 - 7:40] +// CHECK: CXXAccessSpecifier=:10:1 (Definition) Extent=[10:1 - 10:53] +// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50] +// CHECK: CXXMethod=inlineMethod:12:8 (Definition) Extent=[12:3 - 12:25] +// CHECK: attribute(annotate)=investigations Extent=[10:24 - 10:50] +// CHECK: CompoundStmt= Extent=[12:23 - 12:25] +// CHECK: CXXAccessSpecifier=:14:1 (Definition) Extent=[14:1 - 14:11] +// CHECK: CXXMethod=methodWithoutAttribute:16:8 Extent=[16:3 - 16:32] diff --git a/test/Parser/access-spec-attrs.cpp b/test/Parser/access-spec-attrs.cpp new file mode 100644 index 0000000000..4fa5975811 --- /dev/null +++ b/test/Parser/access-spec-attrs.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify + +struct X { +public __attribute__((unavailable)): // expected-error {{access specifier can only have annotation attributes}} + void foo(); +private __attribute__((annotate("foobar"))): + void bar(); +}; + +void f(X x) { + x.foo(); +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 71d9462a01..5748d6bdb7 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3200,6 +3200,11 @@ CXString clang_getCursorSpelling(CXCursor C) { if (clang_isDeclaration(C.kind)) return getDeclSpelling(getCursorDecl(C)); + if (C.kind == CXCursor_AnnotateAttr) { + AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C)); + return createCXString(AA->getAnnotation()); + } + return createCXString(""); } @@ -3521,6 +3526,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("attribute(final)"); case CXCursor_CXXOverrideAttr: return createCXString("attribute(override)"); + case CXCursor_AnnotateAttr: + return createCXString("attribute(annotate)"); case CXCursor_PreprocessingDirective: return createCXString("preprocessing directive"); case CXCursor_MacroDefinition: diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 45f3fa8c2b..db27500143 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -45,6 +45,7 @@ static CXCursorKind GetCursorKind(const Attr *A) { case attr::IBOutletCollection: return CXCursor_IBOutletCollectionAttr; case attr::Final: return CXCursor_CXXFinalAttr; case attr::Override: return CXCursor_CXXOverrideAttr; + case attr::Annotate: return CXCursor_AnnotateAttr; } return CXCursor_UnexposedAttr; |