diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2012-02-01 23:24:59 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2012-02-01 23:24:59 +0000 |
commit | 20039ae1d9f520d8395899d807473b638fb48688 (patch) | |
tree | f7efa9d92a205b8c93f01c0af08a5c7eee331c37 /lib/Sema/SemaAttr.cpp | |
parent | 52b6236427e7b608eadaac2bf8f5a24dd16a1130 (diff) |
Reject mismatched "#pragma GCC visibility push" and "#pragma GCC visibility pop".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149559 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaAttr.cpp')
-rw-r--r-- | lib/Sema/SemaAttr.cpp | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 0859cb727b..8b438a4801 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -365,7 +365,7 @@ void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType, } PushPragmaVisibility(*this, type, PragmaLoc); } else { - PopPragmaVisibility(); + PopPragmaVisibility(false, PragmaLoc); } } @@ -383,23 +383,44 @@ void Sema::ActOnPragmaFPContract(tok::OnOffSwitch OOS) { } } -void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr) { +void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, + SourceLocation Loc) { // Visibility calculations will consider the namespace's visibility. // Here we just want to note that we're in a visibility context // which overrides any enclosing #pragma context, but doesn't itself // contribute visibility. - PushPragmaVisibility(*this, NoVisibility, SourceLocation()); + PushPragmaVisibility(*this, NoVisibility, Loc); } -void Sema::PopPragmaVisibility() { - // Pop visibility from stack, if there is one on the stack. - if (VisContext) { - VisStack *Stack = static_cast<VisStack*>(VisContext); +void Sema::PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc) { + if (!VisContext) { + Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch); + return; + } + + // Pop visibility from stack + VisStack *Stack = static_cast<VisStack*>(VisContext); - Stack->pop_back(); - // To simplify the implementation, never keep around an empty stack. - if (Stack->empty()) - FreeVisContext(); + const std::pair<unsigned, SourceLocation> *Back = &Stack->back(); + bool StartsWithPragma = Back->first != NoVisibility; + if (StartsWithPragma && IsNamespaceEnd) { + Diag(Back->second, diag::err_pragma_push_visibility_mismatch); + Diag(EndLoc, diag::note_surrounding_namespace_ends_here); + + // For better error recovery, eat all pushes inside the namespace. + do { + Stack->pop_back(); + Back = &Stack->back(); + StartsWithPragma = Back->first != NoVisibility; + } while (StartsWithPragma); + } else if (!StartsWithPragma && !IsNamespaceEnd) { + Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch); + Diag(Back->second, diag::note_surrounding_namespace_starts_here); + return; } - // FIXME: Add diag for pop without push. + + Stack->pop_back(); + // To simplify the implementation, never keep around an empty stack. + if (Stack->empty()) + FreeVisContext(); } |