Allow for annotate attributes after access specifiers. When such

attributes are found, propagate them to subsequent declarations.

llvm-svn: 141861
This commit is contained in:
Erik Verbruggen 2011-10-13 09:41:32 +00:00
parent 25f6d3e321
commit ca98f2a63f
13 changed files with 131 additions and 27 deletions

View File

@ -1830,7 +1830,8 @@ enum CXCursorKind {
CXCursor_IBOutletCollectionAttr = 403, CXCursor_IBOutletCollectionAttr = 403,
CXCursor_CXXFinalAttr = 404, CXCursor_CXXFinalAttr = 404,
CXCursor_CXXOverrideAttr = 405, CXCursor_CXXOverrideAttr = 405,
CXCursor_LastAttr = CXCursor_CXXOverrideAttr, CXCursor_AnnotateAttr = 406,
CXCursor_LastAttr = CXCursor_AnnotateAttr,
/* Preprocessing */ /* Preprocessing */
CXCursor_PreprocessingDirective = 500, CXCursor_PreprocessingDirective = 500,

View File

@ -1365,6 +1365,8 @@ def err_attr_objc_ownership_redundant : Error<
"the type %0 already has retainment attributes set on it">; "the type %0 already has retainment attributes set on it">;
def err_attribute_not_string : Error< def err_attribute_not_string : Error<
"argument to %0 attribute was not a string literal">; "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< def err_attribute_section_invalid_for_target : Error<
"argument to 'section' attribute is not valid for this target: %0">; "argument to 'section' attribute is not valid for this target: %0">;
def err_attribute_section_local_variable : Error< def err_attribute_section_local_variable : Error<

View File

@ -1125,7 +1125,8 @@ private:
void DeallocateParsedClasses(ParsingClass *Class); void DeallocateParsedClasses(ParsingClass *Class);
void PopParsingClass(Sema::ParsingClassState); void PopParsingClass(Sema::ParsingClassState);
Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs,
ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo, const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init); const VirtSpecifiers& VS, ExprResult& Init);
void ParseCXXNonStaticMemberInitializer(Decl *VarD); void ParseCXXNonStaticMemberInitializer(Decl *VarD);
@ -1961,7 +1962,7 @@ private:
Decl *TagDecl); Decl *TagDecl);
ExprResult ParseCXXMemberInitializer(bool IsFunction, ExprResult ParseCXXMemberInitializer(bool IsFunction,
SourceLocation &EqualLoc); SourceLocation &EqualLoc);
void ParseCXXClassMemberDeclaration(AccessSpecifier AS, void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
ParsingDeclRAIIObject *DiagsFromTParams = 0); ParsingDeclRAIIObject *DiagsFromTParams = 0);
void ParseConstructorInitializer(Decl *ConstructorDecl); void ParseConstructorInitializer(Decl *ConstructorDecl);
@ -1998,16 +1999,19 @@ private:
// C++ 14.1: Template Parameters [temp.param] // C++ 14.1: Template Parameters [temp.param]
Decl *ParseDeclarationStartingWithTemplate(unsigned Context, Decl *ParseDeclarationStartingWithTemplate(unsigned Context,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
AccessSpecifier AS = AS_none); AccessSpecifier AS = AS_none,
AttributeList *AccessAttrs = 0);
Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context, Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
AccessSpecifier AS); AccessSpecifier AS,
AttributeList *AccessAttrs);
Decl *ParseSingleDeclarationAfterTemplate( Decl *ParseSingleDeclarationAfterTemplate(
unsigned Context, unsigned Context,
const ParsedTemplateInfo &TemplateInfo, const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromParams, ParsingDeclRAIIObject &DiagsFromParams,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
AccessSpecifier AS=AS_none); AccessSpecifier AS=AS_none,
AttributeList *AccessAttrs = 0);
bool ParseTemplateParameters(unsigned Depth, bool ParseTemplateParameters(unsigned Depth,
SmallVectorImpl<Decl*> &TemplateParams, SmallVectorImpl<Decl*> &TemplateParams,
SourceLocation &LAngleLoc, SourceLocation &LAngleLoc,

View File

@ -1838,6 +1838,8 @@ public:
bool NonInheritable = true, bool Inheritable = true); bool NonInheritable = true, bool Inheritable = true);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL,
bool NonInheritable = true, bool Inheritable = true); bool NonInheritable = true, bool Inheritable = true);
bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
const AttributeList *AttrList);
void checkUnusedDeclAttributes(Declarator &D); void checkUnusedDeclAttributes(Declarator &D);
@ -3414,9 +3416,10 @@ public:
bool isCurrentClassName(const IdentifierInfo &II, Scope *S, bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
const CXXScopeSpec *SS = 0); const CXXScopeSpec *SS = 0);
Decl *ActOnAccessSpecifier(AccessSpecifier Access, bool ActOnAccessSpecifier(AccessSpecifier Access,
SourceLocation ASLoc, SourceLocation ASLoc,
SourceLocation ColonLoc); SourceLocation ColonLoc,
AttributeList *Attrs = 0);
Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
Declarator &D, Declarator &D,

View File

@ -21,7 +21,9 @@ using namespace clang;
/// ParseCXXInlineMethodDef - We parsed and verified that the specified /// ParseCXXInlineMethodDef - We parsed and verified that the specified
/// Declarator is a well formed C++ inline method definition. Now lex its body /// 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. /// 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 ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init) { const VirtSpecifiers& VS, ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
@ -43,6 +45,8 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
move(TemplateParams), 0, move(TemplateParams), 0,
VS, /*HasInit=*/false); VS, /*HasInit=*/false);
if (FnD) { if (FnD) {
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs,
false, true);
bool TypeSpecContainsAuto bool TypeSpecContainsAuto
= D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
if (Init.get()) if (Init.get())

View File

@ -1577,6 +1577,7 @@ bool Parser::isCXX0XFinalKeyword() const {
/// '=' constant-expression /// '=' constant-expression
/// ///
void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
AttributeList *AccessAttrs,
const ParsedTemplateInfo &TemplateInfo, const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject *TemplateDiags) { ParsingDeclRAIIObject *TemplateDiags) {
if (Tok.is(tok::at)) { if (Tok.is(tok::at)) {
@ -1643,7 +1644,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
"Nested template improperly parsed?"); "Nested template improperly parsed?");
SourceLocation DeclEnd; SourceLocation DeclEnd;
ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
AS); AS, AccessAttrs);
return; return;
} }
@ -1652,7 +1653,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// __extension__ silences extension warnings in the subexpression. // __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this. ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken(); 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 // 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 = 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) { for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
LateParsedAttrs[i]->setDecl(FunDecl); LateParsedAttrs[i]->setDecl(FunDecl);
@ -1867,6 +1870,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
move(TemplateParams), move(TemplateParams),
BitfieldSize.release(), BitfieldSize.release(),
VS, HasDeferredInitializer); VS, HasDeferredInitializer);
if (AccessAttrs)
Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs,
false, true);
} }
// Set the Decl for any late parsed attributes // Set the Decl for any late parsed attributes
@ -2109,6 +2115,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
CurAS = AS_private; CurAS = AS_private;
else else
CurAS = AS_public; CurAS = AS_public;
ParsedAttributes AccessAttrs(AttrFactory);
if (TagDecl) { if (TagDecl) {
// While we still have something to read, read the member-declarations. // While we still have something to read, read the member-declarations.
@ -2137,9 +2144,17 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
SourceLocation ASLoc = Tok.getLocation(); SourceLocation ASLoc = Tok.getLocation();
unsigned TokLength = Tok.getLength(); unsigned TokLength = Tok.getLength();
ConsumeToken(); ConsumeToken();
AccessAttrs.clear();
MaybeParseGNUAttributes(AccessAttrs);
SourceLocation EndLoc; SourceLocation EndLoc;
if (Tok.is(tok::colon)) { if (Tok.is(tok::colon)) {
EndLoc = Tok.getLocation(); EndLoc = Tok.getLocation();
if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
AccessAttrs.getList())) {
// found another attribute than only annotations
AccessAttrs.clear();
}
ConsumeToken(); ConsumeToken();
} else if (Tok.is(tok::semi)) { } else if (Tok.is(tok::semi)) {
EndLoc = Tok.getLocation(); EndLoc = Tok.getLocation();
@ -2158,7 +2173,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// FIXME: Make sure we don't have a template here. // FIXME: Make sure we don't have a template here.
// Parse all the comma separated declarators. // Parse all the comma separated declarators.
ParseCXXClassMemberDeclaration(CurAS); ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
} }
T.consumeClose(); T.consumeClose();
@ -2779,7 +2794,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
} }
// Parse all the comma separated declarators. // Parse all the comma separated declarators.
ParseCXXClassMemberDeclaration(CurAS); ParseCXXClassMemberDeclaration(CurAS, 0);
} }
if (Tok.isNot(tok::r_brace)) { if (Tok.isNot(tok::r_brace)) {

View File

@ -26,14 +26,16 @@ using namespace clang;
Decl * Decl *
Parser::ParseDeclarationStartingWithTemplate(unsigned Context, Parser::ParseDeclarationStartingWithTemplate(unsigned Context,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
AccessSpecifier AS) { AccessSpecifier AS,
AttributeList *AccessAttrs) {
ObjCDeclContextSwitch ObjCDC(*this); ObjCDeclContextSwitch ObjCDC(*this);
if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(), return ParseExplicitInstantiation(SourceLocation(), ConsumeToken(),
DeclEnd); DeclEnd);
} }
return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS); return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS,
AccessAttrs);
} }
/// \brief RAII class that manages the template parameter depth. /// \brief RAII class that manages the template parameter depth.
@ -77,7 +79,8 @@ namespace {
Decl * Decl *
Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
AccessSpecifier AS) { AccessSpecifier AS,
AttributeList *AccessAttrs) {
assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
"Token does not start a template declaration."); "Token does not start a template declaration.");
@ -161,7 +164,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
isSpecialization, isSpecialization,
LastParamListWasEmpty), LastParamListWasEmpty),
ParsingTemplateParams, ParsingTemplateParams,
DeclEnd, AS); DeclEnd, AS, AccessAttrs);
} }
/// \brief Parse a single declaration that declares a template, /// \brief Parse a single declaration that declares a template,
@ -190,13 +193,15 @@ Parser::ParseSingleDeclarationAfterTemplate(
const ParsedTemplateInfo &TemplateInfo, const ParsedTemplateInfo &TemplateInfo,
ParsingDeclRAIIObject &DiagsFromTParams, ParsingDeclRAIIObject &DiagsFromTParams,
SourceLocation &DeclEnd, SourceLocation &DeclEnd,
AccessSpecifier AS) { AccessSpecifier AS,
AttributeList *AccessAttrs) {
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
"Template information required"); "Template information required");
if (Context == Declarator::MemberContext) { if (Context == Declarator::MemberContext) {
// We are parsing a member template. // We are parsing a member template.
ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams); ParseCXXClassMemberDeclaration(AS, AccessAttrs, TemplateInfo,
&DiagsFromTParams);
return 0; return 0;
} }

View File

@ -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 /// checkUnusedDeclAttributes - Check a list of attributes to see if it
/// contains any decl attributes that we should warn about. /// contains any decl attributes that we should warn about.
static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) { static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) {

View File

@ -1376,14 +1376,15 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. /// ActOnAccessSpecifier - Parsed an access specifier followed by a colon.
Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access, bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
SourceLocation ASLoc, SourceLocation ASLoc,
SourceLocation ColonLoc) { SourceLocation ColonLoc,
AttributeList *Attrs) {
assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); assert(Access != AS_none && "Invalid kind for syntactic access specifier!");
AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext,
ASLoc, ColonLoc); ASLoc, ColonLoc);
CurContext->addHiddenDecl(ASDecl); CurContext->addHiddenDecl(ASDecl);
return ASDecl; return ProcessAccessDeclAttributeList(ASDecl, Attrs);
} }
/// CheckOverrideControl - Check C++0x override control semantics. /// CheckOverrideControl - Check C++0x override control semantics.

View File

@ -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]

View File

@ -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();
}

View File

@ -3200,6 +3200,11 @@ CXString clang_getCursorSpelling(CXCursor C) {
if (clang_isDeclaration(C.kind)) if (clang_isDeclaration(C.kind))
return getDeclSpelling(getCursorDecl(C)); return getDeclSpelling(getCursorDecl(C));
if (C.kind == CXCursor_AnnotateAttr) {
AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C));
return createCXString(AA->getAnnotation());
}
return createCXString(""); return createCXString("");
} }
@ -3521,6 +3526,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("attribute(final)"); return createCXString("attribute(final)");
case CXCursor_CXXOverrideAttr: case CXCursor_CXXOverrideAttr:
return createCXString("attribute(override)"); return createCXString("attribute(override)");
case CXCursor_AnnotateAttr:
return createCXString("attribute(annotate)");
case CXCursor_PreprocessingDirective: case CXCursor_PreprocessingDirective:
return createCXString("preprocessing directive"); return createCXString("preprocessing directive");
case CXCursor_MacroDefinition: case CXCursor_MacroDefinition:

View File

@ -45,6 +45,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
case attr::IBOutletCollection: return CXCursor_IBOutletCollectionAttr; case attr::IBOutletCollection: return CXCursor_IBOutletCollectionAttr;
case attr::Final: return CXCursor_CXXFinalAttr; case attr::Final: return CXCursor_CXXFinalAttr;
case attr::Override: return CXCursor_CXXOverrideAttr; case attr::Override: return CXCursor_CXXOverrideAttr;
case attr::Annotate: return CXCursor_AnnotateAttr;
} }
return CXCursor_UnexposedAttr; return CXCursor_UnexposedAttr;