forked from OSchip/llvm-project
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:
parent
25f6d3e321
commit
ca98f2a63f
|
@ -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,
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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);
|
||||
|
@ -1998,16 +1999,19 @@ private:
|
|||
// C++ 14.1: Template Parameters [temp.param]
|
||||
Decl *ParseDeclarationStartingWithTemplate(unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
AccessSpecifier AS = AS_none);
|
||||
AccessSpecifier AS = AS_none,
|
||||
AttributeList *AccessAttrs = 0);
|
||||
Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context,
|
||||
SourceLocation &DeclEnd,
|
||||
AccessSpecifier AS);
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
bool ActOnAccessSpecifier(AccessSpecifier Access,
|
||||
SourceLocation ASLoc,
|
||||
SourceLocation ColonLoc);
|
||||
SourceLocation ColonLoc,
|
||||
AttributeList *Attrs = 0);
|
||||
|
||||
Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
|
||||
Declarator &D,
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1376,14 +1376,15 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ActOnAccessSpecifier - Parsed an access specifier followed by a colon.
|
||||
Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access,
|
||||
bool Sema::ActOnAccessSpecifier(AccessSpecifier Access,
|
||||
SourceLocation ASLoc,
|
||||
SourceLocation ColonLoc) {
|
||||
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.
|
||||
|
|
|
@ -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]
|
|
@ -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();
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue