diff options
author | Erik Pilkington <erik.pilkington@gmail.com> | 2018-10-29 02:29:21 +0000 |
---|---|---|
committer | Erik Pilkington <erik.pilkington@gmail.com> | 2018-10-29 02:29:21 +0000 |
commit | a7cc6b360fe976c9105968d73f60e26172dc7b77 (patch) | |
tree | e02f473cba9c5e5fc4eed3653a5aaec219c1f908 /clang/lib | |
parent | 36d9746630fd4fb71fef627057fdd5b899cfd221 (diff) | |
download | bcm5719-llvm-a7cc6b360fe976c9105968d73f60e26172dc7b77.tar.gz bcm5719-llvm-a7cc6b360fe976c9105968d73f60e26172dc7b77.zip |
Support for groups of attributes in #pragma clang attribute
This commit enables pushing an empty #pragma clang attribute push, then adding
multiple attributes to it, then popping them all with #pragma clang attribute
pop, just like #pragma clang diagnostic. We still support the current way of
adding these, #pragma clang attribute push(__attribute__((...))), by treating it
like a combined push/attribute. This is needed to create macros like:
DO_SOMETHING_BEGIN(attr1, attr2, attr3)
// ...
DO_SOMETHING_END
rdar://45496947
Differential revision: https://reviews.llvm.org/D53621
llvm-svn: 345486
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParsePragma.cpp | 58 | ||||
-rw-r--r-- | clang/lib/Sema/SemaAttr.cpp | 72 |
2 files changed, 84 insertions, 46 deletions
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 26b363f280c..35072a739b9 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1133,7 +1133,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { namespace { struct PragmaAttributeInfo { - enum ActionType { Push, Pop }; + enum ActionType { Push, Pop, Attribute }; ParsedAttributes &Attributes; ActionType Action; ArrayRef<Token> Tokens; @@ -1394,8 +1394,16 @@ void Parser::HandlePragmaAttribute() { return; } // Parse the actual attribute with its arguments. - assert(Info->Action == PragmaAttributeInfo::Push && - "Unexpected #pragma attribute command"); + assert(Info->Action == PragmaAttributeInfo::Push || + Info->Action == PragmaAttributeInfo::Attribute && + "Unexpected #pragma attribute command"); + + if (Info->Action == PragmaAttributeInfo::Push && Info->Tokens.empty()) { + ConsumeAnnotationToken(); + Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc); + return; + } + PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false); ConsumeAnnotationToken(); @@ -1542,8 +1550,12 @@ void Parser::HandlePragmaAttribute() { // Consume the eof terminator token. ConsumeToken(); - Actions.ActOnPragmaAttributePush(Attribute, PragmaLoc, - std::move(SubjectMatchRules)); + // Handle a mixed push/attribute by desurging to a push, then an attribute. + if (Info->Action == PragmaAttributeInfo::Push) + Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc); + + Actions.ActOnPragmaAttributeAttribute(Attribute, PragmaLoc, + std::move(SubjectMatchRules)); } // #pragma GCC visibility comes in two variants: @@ -3104,6 +3116,8 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma( /// The syntax is: /// \code /// #pragma clang attribute push(attribute, subject-set) +/// #pragma clang attribute push +/// #pragma clang attribute (attribute, subject-set) /// #pragma clang attribute pop /// \endcode /// @@ -3122,25 +3136,33 @@ void PragmaAttributeHandler::HandlePragma(Preprocessor &PP, auto *Info = new (PP.getPreprocessorAllocator()) PragmaAttributeInfo(AttributesForPragmaAttribute); - // Parse the 'push' or 'pop'. - if (Tok.isNot(tok::identifier)) { - PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_push_pop); + if (!Tok.isOneOf(tok::identifier, tok::l_paren)) { + PP.Diag(Tok.getLocation(), + diag::err_pragma_attribute_expected_push_pop_paren); return; } - const auto *II = Tok.getIdentifierInfo(); - if (II->isStr("push")) - Info->Action = PragmaAttributeInfo::Push; - else if (II->isStr("pop")) - Info->Action = PragmaAttributeInfo::Pop; + + // Determine what action this pragma clang attribute represents. + if (Tok.is(tok::l_paren)) + Info->Action = PragmaAttributeInfo::Attribute; else { - PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument) - << PP.getSpelling(Tok); - return; + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("push")) + Info->Action = PragmaAttributeInfo::Push; + else if (II->isStr("pop")) + Info->Action = PragmaAttributeInfo::Pop; + else { + PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument) + << PP.getSpelling(Tok); + return; + } + + PP.Lex(Tok); } - PP.Lex(Tok); // Parse the actual attribute. - if (Info->Action == PragmaAttributeInfo::Push) { + if ((Info->Action == PragmaAttributeInfo::Push && Tok.isNot(tok::eod)) || + Info->Action == PragmaAttributeInfo::Attribute) { if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; return; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 8024e1a0515..f6ac9b44a83 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -520,9 +520,9 @@ attrMatcherRuleListToString(ArrayRef<attr::SubjectMatchRule> Rules) { } // end anonymous namespace -void Sema::ActOnPragmaAttributePush(ParsedAttr &Attribute, - SourceLocation PragmaLoc, - attr::ParsedSubjectMatchRuleSet Rules) { +void Sema::ActOnPragmaAttributeAttribute( + ParsedAttr &Attribute, SourceLocation PragmaLoc, + attr::ParsedSubjectMatchRuleSet Rules) { SmallVector<attr::SubjectMatchRule, 4> SubjectMatchRules; // Gather the subject match rules that are supported by the attribute. SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> @@ -622,48 +622,64 @@ void Sema::ActOnPragmaAttributePush(ParsedAttr &Attribute, Diagnostic << attrMatcherRuleListToString(ExtraRules); } - PragmaAttributeStack.push_back( + if (PragmaAttributeStack.empty()) { + Diag(PragmaLoc, diag::err_pragma_attr_attr_no_push); + return; + } + + PragmaAttributeStack.back().Entries.push_back( {PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false}); } +void Sema::ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc) { + PragmaAttributeStack.emplace_back(); + PragmaAttributeStack.back().Loc = PragmaLoc; +} + void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc) { if (PragmaAttributeStack.empty()) { Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch); return; } - const PragmaAttributeEntry &Entry = PragmaAttributeStack.back(); - if (!Entry.IsUsed) { - assert(Entry.Attribute && "Expected an attribute"); - Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused) - << Entry.Attribute->getName(); - Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here); + + for (const PragmaAttributeEntry &Entry : + PragmaAttributeStack.back().Entries) { + if (!Entry.IsUsed) { + assert(Entry.Attribute && "Expected an attribute"); + Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused) + << Entry.Attribute->getName(); + Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here); + } } + PragmaAttributeStack.pop_back(); } void Sema::AddPragmaAttributes(Scope *S, Decl *D) { if (PragmaAttributeStack.empty()) return; - for (auto &Entry : PragmaAttributeStack) { - ParsedAttr *Attribute = Entry.Attribute; - assert(Attribute && "Expected an attribute"); - - // Ensure that the attribute can be applied to the given declaration. - bool Applies = false; - for (const auto &Rule : Entry.MatchRules) { - if (Attribute->appliesToDecl(D, Rule)) { - Applies = true; - break; + for (auto &Group : PragmaAttributeStack) { + for (auto &Entry : Group.Entries) { + ParsedAttr *Attribute = Entry.Attribute; + assert(Attribute && "Expected an attribute"); + + // Ensure that the attribute can be applied to the given declaration. + bool Applies = false; + for (const auto &Rule : Entry.MatchRules) { + if (Attribute->appliesToDecl(D, Rule)) { + Applies = true; + break; + } } + if (!Applies) + continue; + Entry.IsUsed = true; + PragmaAttributeCurrentTargetDecl = D; + ParsedAttributesView Attrs; + Attrs.addAtEnd(Attribute); + ProcessDeclAttributeList(S, D, Attrs); + PragmaAttributeCurrentTargetDecl = nullptr; } - if (!Applies) - continue; - Entry.IsUsed = true; - PragmaAttributeCurrentTargetDecl = D; - ParsedAttributesView Attrs; - Attrs.addAtEnd(Attribute); - ProcessDeclAttributeList(S, D, Attrs); - PragmaAttributeCurrentTargetDecl = nullptr; } } |