зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
f0d9d8b793
Коммит
90f1450c10
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче