diff options
author | Erik Pilkington <erik.pilkington@gmail.com> | 2018-12-20 22:32:04 +0000 |
---|---|---|
committer | Erik Pilkington <erik.pilkington@gmail.com> | 2018-12-20 22:32:04 +0000 |
commit | 5af7f70eef9405bdaa895370fc4702b47f0e953a (patch) | |
tree | 71e0ead9b6d8a627059ec57cd3a6d6c9e0e510e1 /lib/Sema/SemaAttr.cpp | |
parent | 5faf6e9d41afa74a447da0b47349e4888e59e466 (diff) | |
download | clang-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.cpp | 40 |
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) { |