зеркало из https://github.com/microsoft/clang-1.git
A couple of tweaks to the visibility rules:
- tags with C linkage should ignore visibility=hidden - functions and variables with explicit visibility attributes should ignore the linkage of their types Either of these should be sufficient to fix PR8457. Also, FileCheck-ize a test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117351 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
1235b0ebb1
Коммит
ac65c6208d
|
@ -816,6 +816,10 @@ public:
|
|||
/// C++0x scoped enums), and C++ linkage specifications.
|
||||
bool isTransparentContext() const;
|
||||
|
||||
/// \brief Determines whether this context is, or is nested within,
|
||||
/// a C++ extern "C" linkage spec.
|
||||
bool isExternCContext() const;
|
||||
|
||||
/// \brief Determine whether this declaration context is equivalent
|
||||
/// to the declaration context DC.
|
||||
bool Equals(const DeclContext *DC) const {
|
||||
|
|
|
@ -212,9 +212,13 @@ static LVPair getLVForNamespaceScopeDecl(const NamedDecl *D) {
|
|||
// given variable or function shall be identical...
|
||||
// C does not have an equivalent rule.
|
||||
//
|
||||
// Ignore this if we've got an explicit attribute; the user
|
||||
// probably knows what they're doing.
|
||||
//
|
||||
// Note that we don't want to make the variable non-external
|
||||
// because of this, but unique-external linkage suits us.
|
||||
if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) {
|
||||
if (Context.getLangOptions().CPlusPlus && !Var->isExternC() &&
|
||||
!Var->hasAttr<VisibilityAttr>()) {
|
||||
LVPair TypeLV = Var->getType()->getLinkageAndVisibility();
|
||||
if (TypeLV.first != ExternalLinkage)
|
||||
return LVPair(UniqueExternalLinkage, DefaultVisibility);
|
||||
|
@ -247,7 +251,8 @@ static LVPair getLVForNamespaceScopeDecl(const NamedDecl *D) {
|
|||
} else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
|
||||
// Modify the function's LV by the LV of its type unless this is
|
||||
// C or extern "C". See the comment above about variables.
|
||||
if (Context.getLangOptions().CPlusPlus && !Function->isExternC()) {
|
||||
if (Context.getLangOptions().CPlusPlus && !Function->isExternC() &&
|
||||
!Function->hasAttr<VisibilityAttr>()) {
|
||||
LVPair TypeLV = Function->getType()->getLinkageAndVisibility();
|
||||
if (TypeLV.first != ExternalLinkage)
|
||||
return LVPair(UniqueExternalLinkage, DefaultVisibility);
|
||||
|
@ -321,8 +326,11 @@ static LVPair getLVForNamespaceScopeDecl(const NamedDecl *D) {
|
|||
ConsiderDashFVisibility = false;
|
||||
}
|
||||
|
||||
// Consider -fvisibility unless the type has C linkage.
|
||||
if (ConsiderDashFVisibility)
|
||||
ConsiderDashFVisibility = Tag->isDefinition();
|
||||
ConsiderDashFVisibility =
|
||||
(Context.getLangOptions().CPlusPlus &&
|
||||
!Tag->getDeclContext()->isExternCContext());
|
||||
|
||||
// - an enumerator belonging to an enumeration with external linkage;
|
||||
} else if (isa<EnumConstantDecl>(D)) {
|
||||
|
|
|
@ -529,6 +529,17 @@ bool DeclContext::isTransparentContext() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DeclContext::isExternCContext() const {
|
||||
const DeclContext *DC = this;
|
||||
while (DC->DeclKind != Decl::TranslationUnit) {
|
||||
if (DC->DeclKind == Decl::LinkageSpec)
|
||||
return cast<LinkageSpecDecl>(DC)->getLanguage()
|
||||
== LinkageSpecDecl::lang_c;
|
||||
DC = DC->getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeclContext::Encloses(const DeclContext *DC) const {
|
||||
if (getPrimaryContext() != this)
|
||||
return getPrimaryContext()->Encloses(DC);
|
||||
|
|
|
@ -1,33 +1,34 @@
|
|||
// RUN: %clang_cc1 -triple i386-unknown-unknown -fvisibility default -emit-llvm -o %t %s
|
||||
// RUN: grep '@g_com = common global i32 0' %t
|
||||
// RUN: grep '@g_def = global i32 0' %t
|
||||
// RUN: grep '@g_ext = external global i32' %t
|
||||
// RUN: grep '@g_deferred = internal global' %t
|
||||
// RUN: grep 'declare void @f_ext()' %t
|
||||
// RUN: grep 'define internal void @f_deferred()' %t
|
||||
// RUN: grep 'define i32 @f_def()' %t
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -fvisibility protected -emit-llvm -o %t %s
|
||||
// RUN: grep '@g_com = common protected global i32 0' %t
|
||||
// RUN: grep '@g_def = protected global i32 0' %t
|
||||
// RUN: grep '@g_ext = external global i32' %t
|
||||
// RUN: grep '@g_deferred = internal global' %t
|
||||
// RUN: grep 'declare void @f_ext()' %t
|
||||
// RUN: grep 'define internal void @f_deferred()' %t
|
||||
// RUN: grep 'define protected i32 @f_def()' %t
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -fvisibility hidden -emit-llvm -o %t %s
|
||||
// RUN: grep '@g_com = common hidden global i32 0' %t
|
||||
// RUN: grep '@g_def = hidden global i32 0' %t
|
||||
// RUN: grep '@g_ext = external global i32' %t
|
||||
// RUN: grep '@g_deferred = internal global' %t
|
||||
// RUN: grep 'declare void @f_ext()' %t
|
||||
// RUN: grep 'define internal void @f_deferred()' %t
|
||||
// RUN: grep 'define hidden i32 @f_def()' %t
|
||||
// RUN: %clang_cc1 %s -triple i386-unknown-unknown -fvisibility default -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-DEFAULT
|
||||
// RUN: %clang_cc1 %s -triple i386-unknown-unknown -fvisibility protected -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-PROTECTED
|
||||
// RUN: %clang_cc1 %s -triple i386-unknown-unknown -fvisibility hidden -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-HIDDEN
|
||||
|
||||
// CHECK-DEFAULT: @g_def = global i32 0
|
||||
// CHECK-DEFAULT: @g_com = common global i32 0
|
||||
// CHECK-DEFAULT: @g_ext = external global i32
|
||||
// CHECK-DEFAULT: @g_deferred = internal global
|
||||
// CHECK-PROTECTED: @g_def = protected global i32 0
|
||||
// CHECK-PROTECTED: @g_com = common protected global i32 0
|
||||
// CHECK-PROTECTED: @g_ext = external global i32
|
||||
// CHECK-PROTECTED: @g_deferred = internal global
|
||||
// CHECK-HIDDEN: @g_def = hidden global i32 0
|
||||
// CHECK-HIDDEN: @g_com = common hidden global i32 0
|
||||
// CHECK-HIDDEN: @g_ext = external global i32
|
||||
// CHECK-HIDDEN: @g_deferred = internal global
|
||||
int g_com;
|
||||
int g_def = 0;
|
||||
extern int g_ext;
|
||||
static char g_deferred[] = "hello";
|
||||
|
||||
// CHECK-DEFAULT: define i32 @f_def()
|
||||
// CHECK-DEFAULT: declare void @f_ext()
|
||||
// CHECK-DEFAULT: define internal void @f_deferred()
|
||||
// CHECK-PROTECTED: define protected i32 @f_def()
|
||||
// CHECK-PROTECTED: declare void @f_ext()
|
||||
// CHECK-PROTECTED: define internal void @f_deferred()
|
||||
// CHECK-HIDDEN: define hidden i32 @f_def()
|
||||
// CHECK-HIDDEN: declare void @f_ext()
|
||||
// CHECK-HIDDEN: define internal void @f_deferred()
|
||||
|
||||
extern void f_ext(void);
|
||||
|
||||
static void f_deferred(void) {
|
||||
|
@ -38,3 +39,10 @@ int f_def(void) {
|
|||
f_deferred();
|
||||
return g_com + g_def + g_ext + g_deferred[0];
|
||||
}
|
||||
|
||||
// PR8457
|
||||
// CHECK-DEFAULT: define void @test1(
|
||||
// CHECK-PROTECTED: define void @test1(
|
||||
// CHECK-HIDDEN: define void @test1(
|
||||
struct Test1 { int field; };
|
||||
void __attribute__((visibility("default"))) test1(struct Test1 *v) { }
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
// CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10
|
||||
// CHECK: @_ZN5Test71aE = hidden global
|
||||
// CHECK: @_ZN5Test71bE = global
|
||||
// CHECK: @test9_var = global
|
||||
// CHECK-HIDDEN: @test9_var = global
|
||||
// CHECK: @_ZTVN5Test63fooE = weak_odr hidden constant
|
||||
|
||||
namespace Test1 {
|
||||
|
@ -115,3 +117,19 @@ namespace Test8 {
|
|||
bar();
|
||||
}
|
||||
}
|
||||
|
||||
// PR8457
|
||||
namespace Test9 {
|
||||
extern "C" {
|
||||
struct A { int field; };
|
||||
void DEFAULT test9_fun(struct A *a) { }
|
||||
struct A DEFAULT test9_var; // above
|
||||
}
|
||||
// CHECK: define void @test9_fun(
|
||||
// CHECK-HIDDEN: define void @test9_fun(
|
||||
|
||||
void test() {
|
||||
A a = test9_var;
|
||||
test9_fun(&a);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче