summaryrefslogtreecommitdiff
path: root/lib/Parse/ParsePragma.cpp
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2018-10-29 02:29:21 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2018-10-29 02:29:21 +0000
commit6f1373c1983ea5eb6e0853ae16621e5c0c348df2 (patch)
treebc217aa7d7168a1f07c787f7eab1965a7e4fb2da /lib/Parse/ParsePragma.cpp
parent92a8170754dda7ca8769e784388396cc267fc68b (diff)
downloadclang-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.cpp58
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;