From 90f1450c109fbbd333001165bbd986061f7c4513 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 10 Dec 2010 02:59:44 +0000 Subject: [PATCH] Treat visibility on an enclosing namespace as a non-explicit source of visibility. Fixes PR8713. I've disabled a test which was testing that you can #pragma pop visibility to get out of a namespace's visibility attribute. We should probably just diagnose that as an error unless it's instrumental to someone's system headers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121459 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 6 +++--- lib/AST/Decl.cpp | 14 +++++++++++++ lib/Sema/SemaAttr.cpp | 21 ++++++++++++------- lib/Sema/SemaDeclCXX.cpp | 4 ++-- test/CodeGenCXX/pragma-visibility.cpp | 4 +++- test/CodeGenCXX/visibility-inlines-hidden.cpp | 18 ++++++++++++++++ 6 files changed, 54 insertions(+), 13 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 676934c0ec..541f726e5a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3957,9 +3957,9 @@ public: /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); - /// PushVisibilityAttr - Note that we've entered a context with a - /// visibility attribute. - void PushVisibilityAttr(const VisibilityAttr *Attr); + /// PushNamespaceVisibilityAttr - Note that we've entered a + /// namespace with a visibility attribute. + void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr); /// AddPushedVisibilityAttribute - If '#pragma GCC visibility' was used, /// add an appropriate visibility attribute. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d59fc7a344..f40907cb73 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -249,6 +249,20 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { if (const VisibilityAttr *VA = GetExplicitVisibility(D)) { LV.setVisibility(GetVisibilityFromAttr(VA), true); F.ConsiderGlobalVisibility = false; + } else { + // If we're declared in a namespace with a visibility attribute, + // use that namespace's visibility, but don't call it explicit. + for (const DeclContext *DC = D->getDeclContext(); + !isa(DC); + DC = DC->getParent()) { + if (!isa(DC)) continue; + if (const VisibilityAttr *VA = + cast(DC)->getAttr()) { + LV.setVisibility(GetVisibilityFromAttr(VA), false); + F.ConsiderGlobalVisibility = false; + break; + } + } } } diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 02b8289022..de1e1bf6a2 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -296,8 +296,8 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers, } } -typedef std::vector > VisStack; +typedef std::vector > VisStack; +enum { NoVisibility = (unsigned) -1 }; void Sema::AddPushedVisibilityAttribute(Decl *D) { if (!VisContext) @@ -307,7 +307,11 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) { return; VisStack *Stack = static_cast(VisContext); - VisibilityAttr::VisibilityType type = Stack->back().first; + unsigned rawType = Stack->back().first; + if (rawType == NoVisibility) return; + + VisibilityAttr::VisibilityType type + = (VisibilityAttr::VisibilityType) rawType; SourceLocation loc = Stack->back().second; D->addAttr(::new (Context) VisibilityAttr(loc, Context, type)); @@ -319,8 +323,7 @@ void Sema::FreeVisContext() { VisContext = 0; } -static void PushPragmaVisibility(Sema &S, VisibilityAttr::VisibilityType type, - SourceLocation loc) { +static void PushPragmaVisibility(Sema &S, unsigned type, SourceLocation loc) { // Put visibility on stack. if (!S.VisContext) S.VisContext = new VisStack; @@ -353,8 +356,12 @@ void Sema::ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType, } } -void Sema::PushVisibilityAttr(const VisibilityAttr *Attr) { - PushPragmaVisibility(*this, Attr->getVisibility(), Attr->getLocation()); +void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr) { + // 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()); } void Sema::PopPragmaVisibility() { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index bf9e935981..b5e6321276 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -3194,8 +3194,8 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); - if (const VisibilityAttr *attr = Namespc->getAttr()) - PushVisibilityAttr(attr); + if (const VisibilityAttr *Attr = Namespc->getAttr()) + PushNamespaceVisibilityAttr(Attr); if (II) { // C++ [namespace.def]p2: diff --git a/test/CodeGenCXX/pragma-visibility.cpp b/test/CodeGenCXX/pragma-visibility.cpp index 05de78670a..2dc8bcc74f 100644 --- a/test/CodeGenCXX/pragma-visibility.cpp +++ b/test/CodeGenCXX/pragma-visibility.cpp @@ -63,10 +63,12 @@ namespace n __attribute((visibility("default"))) { #pragma GCC visibility pop } +// We used to test this, but it's insane, so unless it happens in +// headers, we should not support it. namespace n __attribute((visibility("hidden"))) { extern int foofoo; // FIXME: Shouldn't be necessary, but otherwise the pragma // gets to Sema before the namespace! #pragma GCC visibility pop void h() {} - // CHECK: define void @_ZN1n1hEv + // CHECK disabled: define void @_ZN1n1hEv } diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp index 7f92be2abf..760879a2a6 100644 --- a/test/CodeGenCXX/visibility-inlines-hidden.cpp +++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp @@ -79,3 +79,21 @@ namespace test1 { // CHECK: declare void @_ZN5test11A3fooEv // CHECK: declare void @_ZN5test11AD1Ev } + +// PR8713 +namespace test2 { + struct A {}; + template class B {}; + typedef B arg; + + namespace ns __attribute__((visibility("default"))) { + template inline void foo() {} + extern template void foo(); + } + + void test() { + ns::foo(); + } + + // CHECK: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv() +} -- 2.40.0