aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/AST/Decl.cpp14
-rw-r--r--lib/Sema/SemaAttr.cpp21
-rw-r--r--lib/Sema/SemaDeclCXX.cpp4
-rw-r--r--test/CodeGenCXX/pragma-visibility.cpp4
-rw-r--r--test/CodeGenCXX/visibility-inlines-hidden.cpp18
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<TranslationUnitDecl>(DC);
+ DC = DC->getParent()) {
+ if (!isa<NamespaceDecl>(DC)) continue;
+ if (const VisibilityAttr *VA =
+ cast<NamespaceDecl>(DC)->getAttr<VisibilityAttr>()) {
+ 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<std::pair<VisibilityAttr::VisibilityType,
- SourceLocation> > VisStack;
+typedef std::vector<std::pair<unsigned, SourceLocation> > 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<VisStack*>(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<VisibilityAttr>())
- PushVisibilityAttr(attr);
+ if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
+ 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 T> class B {};
+ typedef B<A> arg;
+
+ namespace ns __attribute__((visibility("default"))) {
+ template <class T> inline void foo() {}
+ extern template void foo<arg>();
+ }
+
+ void test() {
+ ns::foo<arg>();
+ }
+
+ // CHECK: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv()
+}