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 | 6f1373c1983ea5eb6e0853ae16621e5c0c348df2 (patch) | |
tree | bc217aa7d7168a1f07c787f7eab1965a7e4fb2da /lib/Parse/ParsePragma.cpp | |
parent | 92a8170754dda7ca8769e784388396cc267fc68b (diff) | |
download | clang-6f1373c1983ea5eb6e0853ae16621e5c0c348df2.tar.gz |
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
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@345486 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParsePragma.cpp')
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 26b363f280..35072a739b 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/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; |