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:
John McCall 2010-10-26 04:59:26 +00:00
Родитель 1235b0ebb1
Коммит ac65c6208d
5 изменённых файлов: 76 добавлений и 27 удалений

Просмотреть файл

@ -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);
}
}