Allow for annotate attributes after access specifiers. When such
attributes are found, propagate them to subsequent declarations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141861 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 9ff04f4..3df1670 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -1830,7 +1830,8 @@
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 38b34a4..36386ec 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1365,6 +1365,8 @@
"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 eed8862..0046f88 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1125,7 +1125,8 @@
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 @@
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 @@
// 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 32bdc73..f4b4c70 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1838,6 +1838,8 @@
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 @@
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 35c181c..b387e9e 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -21,7 +21,9 @@
/// 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 @@
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 decb7f9..607cb88 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1577,6 +1577,7 @@
/// '=' constant-expression
///
void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+ AttributeList *AccessAttrs,
const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject *TemplateDiags) {
if (Tok.is(tok::at)) {
@@ -1643,7 +1644,7 @@
"Nested template improperly parsed?");
SourceLocation DeclEnd;
ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
- AS);
+ AS, AccessAttrs);
return;
}
@@ -1652,7 +1653,8 @@
// __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 @@
}
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 @@
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 @@
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 @@
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 @@
// 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 @@
}
// 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 4509662..92fe4a5 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -26,14 +26,16 @@
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 @@
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 @@
isSpecialization,
LastParamListWasEmpty),
ParsingTemplateParams,
- DeclEnd, AS);
+ DeclEnd, AS, AccessAttrs);
}
/// \brief Parse a single declaration that declares a template,
@@ -190,13 +193,15 @@
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 f76bb58..69baf79 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -3743,6 +3743,22 @@
}
}
+// 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 32da8cb..a39584a 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1376,14 +1376,15 @@
//===----------------------------------------------------------------------===//
/// 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 0000000..6721371
--- /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 0000000..4fa5975
--- /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 71d9462..5748d6b 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -3200,6 +3200,11 @@
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 @@
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 45f3fa8..db27500 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -45,6 +45,7 @@
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;