summaryrefslogtreecommitdiffstats
path: root/clang/lib
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
commita7cc6b360fe976c9105968d73f60e26172dc7b77 (patch)
treee02f473cba9c5e5fc4eed3653a5aaec219c1f908 /clang/lib
parent36d9746630fd4fb71fef627057fdd5b899cfd221 (diff)
downloadbcm5719-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.cpp58
-rw-r--r--clang/lib/Sema/SemaAttr.cpp72
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;
}
}
OpenPOWER on IntegriCloud