summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaAttr.cpp
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2018-12-20 22:32:04 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2018-12-20 22:32:04 +0000
commit5af7f70eef9405bdaa895370fc4702b47f0e953a (patch)
tree71e0ead9b6d8a627059ec57cd3a6d6c9e0e510e1 /lib/Sema/SemaAttr.cpp
parent5faf6e9d41afa74a447da0b47349e4888e59e466 (diff)
downloadclang-5af7f70eef9405bdaa895370fc4702b47f0e953a.tar.gz
Add support for namespaces on #pragma clang attribute
Namespaces are introduced by adding an "identifier." before a push/pop directive. Pop directives with namespaces can only pop a attribute group that was pushed with the same namespace. Push and pop directives that don't opt into namespaces have the same semantics. This is necessary to prevent a pitfall of using multiple #pragma clang attribute directives spread out in a large file, particularly when macros are involved. It isn't easy to see which pop corripsonds to which push, so its easy to inadvertently pop the wrong group. Differential revision: https://reviews.llvm.org/D55628 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@349845 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaAttr.cpp')
-rw-r--r--lib/Sema/SemaAttr.cpp40
1 files changed, 29 insertions, 11 deletions
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index f6ac9b44a8..2bc1b769f7 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -631,28 +631,46 @@ void Sema::ActOnPragmaAttributeAttribute(
{PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false});
}
-void Sema::ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc) {
+void Sema::ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc,
+ const IdentifierInfo *Namespace) {
PragmaAttributeStack.emplace_back();
PragmaAttributeStack.back().Loc = PragmaLoc;
+ PragmaAttributeStack.back().Namespace = Namespace;
}
-void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc) {
+void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc,
+ const IdentifierInfo *Namespace) {
if (PragmaAttributeStack.empty()) {
- Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch);
+ Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) << 1;
return;
}
- 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);
+ // Dig back through the stack trying to find the most recently pushed group
+ // that in Namespace. Note that this works fine if no namespace is present,
+ // think of push/pops without namespaces as having an implicit "nullptr"
+ // namespace.
+ for (size_t Index = PragmaAttributeStack.size(); Index;) {
+ --Index;
+ if (PragmaAttributeStack[Index].Namespace == Namespace) {
+ for (const PragmaAttributeEntry &Entry :
+ PragmaAttributeStack[Index].Entries) {
+ if (!Entry.IsUsed) {
+ assert(Entry.Attribute && "Expected an attribute");
+ Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused)
+ << *Entry.Attribute;
+ Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here);
+ }
+ }
+ PragmaAttributeStack.erase(PragmaAttributeStack.begin() + Index);
+ return;
}
}
- PragmaAttributeStack.pop_back();
+ if (Namespace)
+ Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch)
+ << 0 << Namespace->getName();
+ else
+ Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) << 1;
}
void Sema::AddPragmaAttributes(Scope *S, Decl *D) {