Nikolas Klauser afc6c2bb9b
[Clang] Allow the use of [[gnu::visibility]] with #pragma clang attribute (#145653)
I don't see any reason this shouldn't be allowed. AFAICT this is only
disabled due to the heuristics used to determine whether it makes sense
to allow the use of an attribute with `#pragma clang attribute`.

This allows libc++ to drop `_LIBCPP_HIDE_FROM_ABI` in a lot of places,
making the library significantly easier to read.
2025-06-26 14:54:15 +02:00

1563 lines
42 KiB
C++

// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fvisibility=hidden -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-HIDDEN
// For clang, "internal" is just an alias for "hidden". We could use it for some
// optimization purposes on 32-bit x86, but it's not worth it.
// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fvisibility=internal -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-HIDDEN
#define HIDDEN __attribute__((visibility("hidden")))
#define PROTECTED __attribute__((visibility("protected")))
#define DEFAULT __attribute__((visibility("default")))
namespace test30 {
// When H is hidden, it should make X hidden, even if the template argument
// is not.
struct H {
};
template<H *T>
struct X {
};
H DEFAULT a;
X<&a> b;
// CHECK: _ZN6test301bE = global
// CHECK-HIDDEN: _ZN6test301bE = hidden global
}
namespace test25 {
template<typename T>
struct X {
template<typename U>
struct definition {
};
};
class DEFAULT A { };
X<int>::definition<A> a;
// CHECK: @_ZN6test251aE = global
// CHECK-HIDDEN: @_ZN6test251aE = hidden global
}
namespace test28 {
class DEFAULT foo {
};
foo myvec;
// CHECK: @_ZN6test285myvecE = global
// CHECK-HIDDEN: @_ZN6test285myvecE = hidden global
}
namespace test29 {
#pragma GCC visibility push(hidden)
struct RECT {
int top;
};
DEFAULT extern RECT data_rect;
RECT data_rect = { -1};
#pragma GCC visibility pop
// CHECK: @_ZN6test299data_rectE = global
// CHECK-HIDDEN: @_ZN6test299data_rectE = global
}
namespace test40 {
template<typename T>
struct foo {
DEFAULT static int bar;
};
template<typename T>
int foo<T>::bar;
template struct foo<int>;
// CHECK: _ZN6test403fooIiE3barE = weak_odr global
// CHECK-HIDDEN: _ZN6test403fooIiE3barE = weak_odr global
}
namespace test41 {
// Unlike gcc we propagate the information that foo not only is hidden, but
// has been explicitly marked as so. This lets us produce a hidden undefined
// reference to bar.
struct HIDDEN foo {};
extern foo bar;
foo *zed() {
return &bar;
}
// CHECK: @_ZN6test413barE = external hidden global
// CHECK-HIDDEN: @_ZN6test413barE = external hidden global
}
namespace test48 {
// Test that we use the visibility of struct foo when instantiating the
// template. Note that is a case where we disagree with gcc, it produces
// a default symbol.
struct HIDDEN foo {
};
DEFAULT foo x;
struct bar {
template<foo *z>
struct zed {
};
};
bar::zed<&x> y;
// CHECK: _ZN6test481yE = hidden global
// CHECK-HIDDEN: _ZN6test481yE = hidden global
}
namespace test72 {
template <class T>
struct foo {
HIDDEN static int var1;
template <class U> HIDDEN static U var2;
};
template <class T> template <class U>
U foo<T>::var2;
extern template struct DEFAULT foo<int>;
int use() {
foo<int> o;
foo<long> p;
return o.var1 + o.var2<int> + p.var1 + p.var2<int>;
}
// CHECK: @_ZN6test723fooIiE4var1E = external hidden global i32
// CHECK-NEXT: @_ZN6test723fooIiE4var2IiEE = linkonce_odr global i32 0
// CHECK-NEXT: @_ZN6test723fooIlE4var1E = external hidden global i32
// CHECK-NEXT: @_ZN6test723fooIlE4var2IiEE = linkonce_odr global i32 0
}
namespace test73 {
struct HIDDEN foo {};
DEFAULT foo da, db, dc, dd;
HIDDEN foo ha, hb, hc, hd;
template<foo *z> DEFAULT int var;
template int var<&da>;
template int DEFAULT var<&db>;
template int HIDDEN var<&dc>;
template int var<&ha>;
template int DEFAULT var<&hb>;
template int HIDDEN var<&hc>;
int use() { return var<&dd> + var<&hd>; }
// CHECK: @_ZN6test733varIXadL_ZNS_2daEEEEE = weak_odr hidden global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2dbEEEEE = weak_odr global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2dcEEEEE = weak_odr hidden global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2haEEEEE = weak_odr hidden global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2hbEEEEE = weak_odr global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2hcEEEEE = weak_odr hidden global i32 0
// CHECK: @_ZN6test733varIXadL_ZNS_2ddEEEEE = linkonce_odr hidden global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2hdEEEEE = linkonce_odr hidden global i32 0
// CHECK-HIDDEN: @_ZN6test733varIXadL_ZNS_2daEEEEE = weak_odr hidden global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2dbEEEEE = weak_odr global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2dcEEEEE = weak_odr hidden global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2haEEEEE = weak_odr hidden global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2hbEEEEE = weak_odr global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2hcEEEEE = weak_odr hidden global i32 0
// CHECK-HIDDEN: @_ZN6test733varIXadL_ZNS_2ddEEEEE = linkonce_odr hidden global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2hdEEEEE = linkonce_odr hidden global i32 0
}
// CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10
// CHECK: @_ZN5Test71aE = hidden global
// CHECK: @_ZN5Test71bE = global
// CHECK: @test9_var = global
// CHECK-HIDDEN: @test9_var = global
// CHECK: @_ZN6Test121A6hiddenE = external hidden global
// CHECK: @_ZN6Test121A7visibleE = external global
// CHECK-HIDDEN: @_ZN6Test121A6hiddenE = external hidden global
// CHECK-HIDDEN: @_ZN6Test121A7visibleE = external global
// CHECK: @_ZN6Test131B1aE = hidden global
// CHECK: @_ZN6Test131C1aE = global
// CHECK-HIDDEN: @_ZN6Test131B1aE = hidden global
// CHECK-HIDDEN: @_ZN6Test131C1aE = global
// CHECK: @_ZN6Test143varE = external global
// CHECK-HIDDEN: @_ZN6Test143varE = external global
// CHECK: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
// CHECK-HIDDEN: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8]
// CHECK: @_ZTVN6test701BE = external hidden unnamed_addr constant { [5 x ptr] }, align 8
// CHECK: @_ZTTN6test701BE = external hidden unnamed_addr constant [2 x ptr], align 8
namespace test27 {
template<typename T>
class C {
class DEFAULT D {
void f();
};
};
template<>
class C<int>::D {
virtual void g();
};
void C<int>::D::g() {
}
// CHECK: _ZTVN6test271CIiE1DE = unnamed_addr constant
// CHECK-HIDDEN: _ZTVN6test271CIiE1DE = unnamed_addr constant
}
// CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden unnamed_addr constant
// CHECK-HIDDEN: @_ZTVN6Test161AIcEE = external unnamed_addr constant
// CHECK-HIDDEN: @_ZTTN6Test161AIcEE = external unnamed_addr constant
// CHECK: @_ZZN6test681fC1EvE4test = linkonce_odr global
// CHECK-HIDDEN: @_ZZN6test681fC1EvE4test = linkonce_odr hidden global
// CHECK: @_ZGVZN6test681fC1EvE4test = linkonce_odr global
// CHECK-HIDDEN: @_ZGVZN6test681fC1EvE4test = linkonce_odr hidden global
// CHECK-HIDDEN: @_ZTVN6test701DE = linkonce_odr hidden unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr null, ptr @_ZTIN6test701DE] }, align 8
// CHECK-HIDDEN: @_ZTTN6test701DE = linkonce_odr hidden unnamed_addr constant [1 x ptr] [ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr] }, ptr @_ZTVN6test701DE, i32 0, i32 0, i32 3)], align 8
// CHECK: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr global
// CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global
// CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64
// CHECK-HIDDEN: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr hidden global i64
namespace Test1 {
// CHECK-LABEL: define hidden void @_ZN5Test11fEv
void HIDDEN f() { }
}
namespace Test2 {
struct HIDDEN A {
void f();
};
// A::f is a member function of a hidden class.
// CHECK-LABEL: define hidden void @_ZN5Test21A1fEv
void A::f() { }
}
namespace Test3 {
struct HIDDEN A {
struct B {
void f();
};
};
// B is a nested class where its parent class is hidden.
// CHECK-LABEL: define hidden void @_ZN5Test31A1B1fEv
void A::B::f() { }
}
namespace Test4 HIDDEN {
int VariableInHiddenNamespace = 10;
// Test4::g is in a hidden namespace.
// CHECK-LABEL: define hidden void @_ZN5Test41gEv
void g() { }
struct DEFAULT A {
void f();
};
// A has default visibility.
// CHECK-LABEL: define void @_ZN5Test41A1fEv
void A::f() { }
}
namespace Test5 {
namespace NS HIDDEN {
// f is in NS which is hidden.
// CHECK-LABEL: define hidden void @_ZN5Test52NS1fEv()
void f() { }
}
namespace NS {
// g is in NS, but this NS decl is not hidden.
// CHECK-LABEL: define void @_ZN5Test52NS1gEv
void g() { }
}
}
namespace Test6 {
struct HIDDEN foo {
foo() { }
void bonk();
virtual void bar() = 0;
virtual void zonk() {}
};
struct barc : public foo {
barc();
virtual void bar();
};
barc::barc() {}
}
namespace Test7 {
class HIDDEN A {};
A a; // top of file
template <A&> struct Aref {
static void foo() {}
};
class B : public A {};
B b; // top of file
// CHECK-LABEL: define linkonce_odr hidden void @_ZN5Test74ArefIL_ZNS_1aEEE3fooEv()
void test() {
Aref<a>::foo();
}
}
namespace Test8 {
void foo();
void bar() {}
// CHECK-HIDDEN-LABEL: define hidden void @_ZN5Test83barEv()
// CHECK-HIDDEN: declare void @_ZN5Test83fooEv()
void test() {
foo();
bar();
}
}
// PR8457
namespace Test9 {
extern "C" {
struct A { int field; };
void DEFAULT test9_fun(struct A *a) { }
struct A DEFAULT test9_var; // above
}
// CHECK-LABEL: define void @test9_fun(
// CHECK-HIDDEN-LABEL: define void @test9_fun(
void test() {
A a = test9_var;
test9_fun(&a);
}
}
// PR8478
namespace Test10 {
struct A;
class DEFAULT B {
void foo(A*);
};
// CHECK-LABEL: define void @_ZN6Test101B3fooEPNS_1AE(
// CHECK-HIDDEN-LABEL: define void @_ZN6Test101B3fooEPNS_1AE(
void B::foo(A*) {}
}
// PR8492
namespace Test11 {
struct A {
void foo() {}
void DEFAULT bar() {}
};
void test() {
A a;
a.foo();
a.bar();
}
// CHECK-LABEL: define linkonce_odr void @_ZN6Test111A3fooEv(
// CHECK-LABEL: define linkonce_odr void @_ZN6Test111A3barEv(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6Test111A3fooEv(
// CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6Test111A3barEv(
}
// Tested at top of file.
namespace Test12 {
struct A {
// This is hidden in all cases: the explicit attribute takes
// priority over -fvisibility on the parent.
static int hidden HIDDEN;
// This is default in all cases because it's only a declaration.
static int visible;
};
void test() {
A::hidden = 0;
A::visible = 0;
}
}
// Tested at top of file.
namespace Test13 {
struct HIDDEN A {};
// Should be hidden in all cases.
struct B {
static A a;
};
A B::a;
// Should be default in all cases.
struct DEFAULT C {
static A a;
};
A C::a;
};
// Tested at top of file.
namespace Test14 {
// Neither the visibility of the type nor -fvisibility=hidden should
// apply to declarations.
extern struct A *var;
struct A *test() { return var; }
}
namespace Test15 {
struct A {};
template <class T> struct Temp {
struct Inner {
static char buffer[0];
};
};
char *test() {
return Temp<A>::Inner::buffer;
}
}
namespace Test16 {
struct Base1 { virtual void foo(); };
struct Base2 : virtual Base1 { virtual void foo(); };
template <class T> struct A : virtual Base1, Base2 {
virtual void foo();
};
extern template struct A<char>;
void test() {
A<char> a;
a.foo();
}
}
namespace Test17 {
struct HIDDEN A {
static void foo();
static void DEFAULT bar();
static void HIDDEN baz();
struct DEFAULT B {
static void foo();
static void DEFAULT bar();
static void HIDDEN baz();
};
};
void test() {
A::foo();
A::bar();
A::baz();
A::B::foo();
A::B::bar();
A::B::baz();
}
// CHECK: declare hidden void @_ZN6Test171A3fooEv()
// CHECK: declare void @_ZN6Test171A3barEv()
// CHECK: declare hidden void @_ZN6Test171A3bazEv()
// CHECK: declare void @_ZN6Test171A1B3fooEv()
// CHECK: declare void @_ZN6Test171A1B3barEv()
// CHECK: declare hidden void @_ZN6Test171A1B3bazEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test171A3fooEv()
// CHECK-HIDDEN: declare void @_ZN6Test171A3barEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test171A3bazEv()
// CHECK-HIDDEN: declare void @_ZN6Test171A1B3fooEv()
// CHECK-HIDDEN: declare void @_ZN6Test171A1B3barEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test171A1B3bazEv()
}
namespace Test18 {
template <class T> struct HIDDEN A {
static void foo();
static void DEFAULT bar();
static void HIDDEN baz();
struct DEFAULT B {
static void foo();
static void DEFAULT bar();
static void HIDDEN baz();
};
};
struct HIDDEN H;
void test() {
A<int>::foo();
A<int>::bar();
A<int>::baz();
A<int>::B::foo();
A<int>::B::bar();
A<int>::B::baz();
A<H>::foo();
A<H>::bar();
A<H>::baz();
A<H>::B::foo();
A<H>::B::bar();
A<H>::B::baz();
}
// CHECK: declare hidden void @_ZN6Test181AIiE3fooEv()
// CHECK: declare void @_ZN6Test181AIiE3barEv()
// CHECK: declare hidden void @_ZN6Test181AIiE3bazEv()
// CHECK: declare void @_ZN6Test181AIiE1B3fooEv()
// CHECK: declare void @_ZN6Test181AIiE1B3barEv()
// CHECK: declare hidden void @_ZN6Test181AIiE1B3bazEv()
// CHECK: declare hidden void @_ZN6Test181AINS_1HEE3fooEv()
// CHECK: declare hidden void @_ZN6Test181AINS_1HEE3barEv()
// CHECK: declare hidden void @_ZN6Test181AINS_1HEE3bazEv()
// CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3fooEv()
// CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3barEv()
// CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3bazEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE3fooEv()
// CHECK-HIDDEN: declare void @_ZN6Test181AIiE3barEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE3bazEv()
// CHECK-HIDDEN: declare void @_ZN6Test181AIiE1B3fooEv()
// CHECK-HIDDEN: declare void @_ZN6Test181AIiE1B3barEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE1B3bazEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3fooEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3barEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3bazEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3fooEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3barEv()
// CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3bazEv()
}
namespace Test19 {
struct A { A(); ~A(); };
// Tested at top of file.
template <class T> void foo() {
static A a;
}
void test() {
foo<int>();
}
}
// Various things with class template specializations.
namespace Test20 {
template <unsigned> struct HIDDEN A {};
// An explicit specialization inherits the explicit visibility of
// the template.
template <> struct A<0> {
static void test0();
static void test1();
};
// CHECK-LABEL: define hidden void @_ZN6Test201AILj0EE5test0Ev()
void A<0>::test0() {}
// CHECK: declare hidden void @_ZN6Test201AILj0EE5test1Ev()
void test1() {
A<0>::test1();
}
// ...unless that's explicitly overridden.
template <> struct DEFAULT A<1> {
static void test2();
static void test3();
};
// CHECK-LABEL: define void @_ZN6Test201AILj1EE5test2Ev()
void A<1>::test2() {}
// CHECK: declare void @_ZN6Test201AILj1EE5test3Ev()
void test3() {
A<1>::test3();
}
// But we should assume that an unknown specialization has the
// explicit visibility settings of the template.
template <class T> struct B {
static void test4() {}
static void test5();
};
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev()
void test4() {
B<A<2> >::test4();
}
// CHECK: declare hidden void @_ZN6Test201BINS_1AILj2EEEE5test5Ev()
void test5() {
B<A<2> >::test5();
}
}
// PR9371
namespace test21 {
enum En { en };
template<En> struct A {
DEFAULT void foo() {}
};
// CHECK-LABEL: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv(
template void A<en>::foo();
}
// Visibility on explicit specializations should take precedence.
namespace test22 {
class A1 {};
class A2 {};
template <class T> struct B {};
template <> struct DEFAULT B<A1> {
static void foo();
static void bar() {}
};
template <> struct B<A2> {
static void foo();
static void bar() {}
};
void test() {
B<A1>::foo();
B<A1>::bar();
B<A2>::foo();
B<A2>::bar();
}
// CHECK: declare void @_ZN6test221BINS_2A1EE3fooEv()
// CHECK-LABEL: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
// CHECK: declare void @_ZN6test221BINS_2A2EE3fooEv()
// CHECK-LABEL: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv()
// CHECK-HIDDEN: declare void @_ZN6test221BINS_2A1EE3fooEv()
// CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv()
// CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv()
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv()
}
namespace PR10113 {
namespace foo DEFAULT {
template<typename T>
class bar {
void zed() {}
};
}
template class foo::bar<char>;
// CHECK-LABEL: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv
struct zed {
};
template class foo::bar<zed>;
// CHECK-LABEL: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN7PR101133foo3barINS_3zedEE3zedEv
}
namespace PR11690 {
template<class T> struct Class {
void size() const {
}
};
template class DEFAULT Class<char>;
// CHECK-LABEL: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv
template<class T> void Method() {}
template DEFAULT void Method<char>();
// CHECK-LABEL: define weak_odr void @_ZN7PR116906MethodIcEEvv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN7PR116906MethodIcEEvv
}
namespace PR11690_2 {
namespace foo DEFAULT {
class bar;
template<typename T1, typename T2 = bar>
class zed {
void bar() {
}
};
}
struct baz {
};
template class foo::zed<baz>;
// CHECK-LABEL: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
}
namespace test23 {
// Having a template argument that is explicitly visible should not make
// the template instantiation visible.
template <typename T>
struct X {
static void f() {
}
};
class DEFAULT A;
void g() {
X<A> y;
y.f();
}
// CHECK-LABEL: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv
}
namespace PR12001 {
template <typename P1>
void Bind(const P1& p1) {
}
class DEFAULT Version { };
void f() {
Bind(Version());
}
// CHECK-LABEL: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_
}
namespace test24 {
class DEFAULT A { };
struct S {
template <typename T>
void mem() {}
};
void test() {
S s;
s.mem<A>();
}
// CHECK-LABEL: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv
}
namespace test26 {
template<typename T>
class C {
DEFAULT void f();
};
template<>
void C<int>::f() { }
// CHECK-LABEL: define void @_ZN6test261CIiE1fEv
// CHECK-HIDDEN-LABEL: define void @_ZN6test261CIiE1fEv
}
namespace test31 {
struct A {
struct HIDDEN B {
static void DEFAULT baz();
};
};
void f() {
A::B::baz();
}
// CHECK: declare void @_ZN6test311A1B3bazEv()
// CHECK-HIDDEN: declare void @_ZN6test311A1B3bazEv()
}
namespace test32 {
struct HIDDEN A {
struct DEFAULT B {
void DEFAULT baz();
};
};
void A::B::baz() {
}
// CHECK-LABEL: define void @_ZN6test321A1B3bazEv
// CHECK-HIDDEN-LABEL: define void @_ZN6test321A1B3bazEv
}
namespace test33 {
template<typename T>
class foo {
void bar() {}
};
struct HIDDEN zed {
};
template class DEFAULT foo<zed>;
// CHECK-LABEL: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test333fooINS_3zedEE3barEv
}
namespace test34 {
struct foo {
};
template<class T>
void bar() {}
template DEFAULT void bar<foo>();
// CHECK-LABEL: define weak_odr void @_ZN6test343barINS_3fooEEEvv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test343barINS_3fooEEEvv
}
namespace test35 {
// This is a really ugly testcase. GCC propagates the DEFAULT in zed's
// definition. It's not really clear what we can do here, because we
// produce the symbols before even seeing the DEFAULT definition of zed.
// FIXME: Maybe the best thing to do here is error? It's certainly hard
// to argue that this ought to be valid.
template<typename T>
struct DEFAULT foo {
void bar() {}
};
class zed;
template class foo<zed>;
class DEFAULT zed {
};
// CHECK-LABEL: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test353fooINS_3zedEE3barEv
}
namespace test36 {
template<typename T1, typename T2>
class foo {
void bar() {}
};
class DEFAULT S1 {};
struct HIDDEN S2 {};
template class foo<S1, S2>;
// CHECK-LABEL: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv
}
namespace test37 {
struct HIDDEN foo {
};
template<class T>
DEFAULT void bar() {}
template DEFAULT void bar<foo>();
// CHECK-LABEL: define weak_odr void @_ZN6test373barINS_3fooEEEvv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test373barINS_3fooEEEvv
}
namespace test38 {
template<typename T>
class DEFAULT foo {
void bar() {}
};
struct HIDDEN zed {
};
template class foo<zed>;
// CHECK-LABEL: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv
}
namespace test39 {
class DEFAULT default_t;
class HIDDEN hidden_t;
template <class T> class A {
template <class U> class B {
HIDDEN void hidden() {}
void noattr() {}
template <class V> void temp() {}
};
};
template class DEFAULT A<hidden_t>;
template class DEFAULT A<hidden_t>::B<hidden_t>;
template void A<hidden_t>::B<hidden_t>::temp<default_t>();
template void A<hidden_t>::B<hidden_t>::temp<hidden_t>();
// CHECK-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv
// CHECK-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv
// CHECK-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv
// GCC produces a default for this one. Why?
// CHECK-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv
// GCC produces a default for this one. Why?
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv
}
namespace test42 {
struct HIDDEN foo {
};
template <class P>
struct bar {
};
template <>
struct HIDDEN bar<foo> {
DEFAULT static void zed();
};
void bar<foo>::zed() {
}
// CHECK-LABEL: define void @_ZN6test423barINS_3fooEE3zedEv
// CHECK-HIDDEN-LABEL: define void @_ZN6test423barINS_3fooEE3zedEv
}
namespace test43 {
struct HIDDEN foo {
};
template <class P>
void bar() {
}
template <>
DEFAULT void bar<foo>() {
}
// CHECK-LABEL: define void @_ZN6test433barINS_3fooEEEvv
// CHECK-HIDDEN-LABEL: define void @_ZN6test433barINS_3fooEEEvv
}
namespace test44 {
template <typename T>
struct foo {
foo() {}
};
namespace {
struct bar;
}
template struct DEFAULT foo<bar>;
foo<bar> x;
// CHECK-LABEL: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev
// CHECK-HIDDEN-LABEL: define internal void @_ZN6test443fooINS_12_GLOBAL__N_13barEEC1Ev
}
namespace test45 {
template <typename T>
struct foo {
template <typename T2>
struct bar {
bar() {};
};
};
namespace {
struct zed;
}
template struct DEFAULT foo<int>::bar<zed>;
foo<int>::bar<zed> x;
// CHECK-LABEL: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev
// CHECK-HIDDEN-LABEL: define internal void @_ZN6test453fooIiE3barINS_12_GLOBAL__N_13zedEEC1Ev
}
namespace test46 {
template <typename T>
void foo() {
}
namespace {
struct bar;
}
template DEFAULT void foo<bar>();
void zed() {
foo<bar>();
}
// CHECK-LABEL: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv
// CHECK-HIDDEN-LABEL: define internal void @_ZN6test463fooINS_12_GLOBAL__N_13barEEEvv
}
namespace test47 {
struct foo {
template <typename T>
static void bar() {
}
};
namespace {
struct zed;
}
template DEFAULT void foo::bar<zed>();
void baz() {
foo::bar<zed>();
}
// CHECK-LABEL: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv
// CHECK-HIDDEN-LABEL: define internal void @_ZN6test473foo3barINS_12_GLOBAL__N_13zedEEEvv
}
namespace test49 {
// Test that we use the visibility of struct foo when instantiating the
// template. Note that is a case where we disagree with gcc, it produces
// a default symbol.
struct HIDDEN foo {
};
DEFAULT foo x;
struct bar {
template<foo *z>
void zed() {
}
};
template void bar::zed<&x>();
// CHECK-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
}
namespace test50 {
// Test that we use the visibility of struct foo when instantiating the
// template. Note that is a case where we disagree with gcc, it produces
// a default symbol.
struct HIDDEN foo {
};
DEFAULT foo x;
template<foo *z>
struct DEFAULT bar {
void zed() {
}
};
template void bar<&x>::zed();
// CHECK-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
}
namespace test51 {
// Test that we use the visibility of struct foo when instantiating the
// template. Note that is a case where we disagree with gcc, it produces
// a default symbol.
struct HIDDEN foo {};
DEFAULT foo da, db, dc, dd, de, df;
HIDDEN foo ha, hb, hc, hd, he, hf;
template<foo *z>
void DEFAULT zed() {
}
template void zed<&da>();
// CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv(
template void DEFAULT zed<&db>();
// CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2dbEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2dbEEEEEvv(
template void HIDDEN zed<&dc>();
// CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2dcEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2dcEEEEEvv(
template void zed<&ha>();
// CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv(
template void DEFAULT zed<&hb>();
// CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2hbEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2hbEEEEEvv(
template void HIDDEN zed<&hc>();
// CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2hcEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2hcEEEEEvv(
#pragma GCC visibility push(hidden)
template void zed<&dd>();
template void zed<&hd>();
template void DEFAULT zed<&he>();
#pragma GCC visibility pop
// CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2ddEEEEEvv(
// CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2hdEEEEEvv(
// CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2heEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2ddEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2hdEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2heEEEEEvv(
void use() {
zed<&df>();
zed<&hf>();
}
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2dfEEEEEvv(
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2hfEEEEEvv(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2dfEEEEEvv(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2hfEEEEEvv(
}
namespace test52 {
// Test that we use the linkage of struct foo when instantiating the
// template. Note that is a case where we disagree with gcc, it produces
// an external symbol.
namespace {
struct foo {
};
}
template<foo *x>
void zed() {
}
void f() {
zed<nullptr>();
}
// CHECK-LABEL: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv
// CHECK-HIDDEN-LABEL: define internal void @_ZN6test523zedILPNS_12_GLOBAL__N_13fooE0EEEvv
}
namespace test53 {
template<typename _Tp > struct vector {
static void _M_fill_insert();
};
#pragma GCC visibility push(hidden)
// GCC doesn't seem to use the visibility of enums at all, we do.
enum zed {v1};
// GCC fails to mark this specialization hidden, we mark it.
template<>
struct vector<int> {
static void _M_fill_insert();
};
void foo() {
vector<unsigned>::_M_fill_insert();
vector<int>::_M_fill_insert();
vector<zed>::_M_fill_insert();
}
#pragma GCC visibility pop
// CHECK: declare void @_ZN6test536vectorIjE14_M_fill_insertEv
// CHECK-HIDDEN: declare void @_ZN6test536vectorIjE14_M_fill_insertEv
// CHECK: declare hidden void @_ZN6test536vectorIiE14_M_fill_insertEv
// CHECK-HIDDEN: declare hidden void @_ZN6test536vectorIiE14_M_fill_insertEv
// CHECK: declare hidden void @_ZN6test536vectorINS_3zedEE14_M_fill_insertEv
// CHECK-HIDDEN: declare hidden void @_ZN6test536vectorINS_3zedEE14_M_fill_insertEv
}
namespace test54 {
template <class T>
struct foo {
static void bar();
};
#pragma GCC visibility push(hidden)
class zed {
zed(const zed &);
};
void bah() {
foo<zed>::bar();
}
#pragma GCC visibility pop
// CHECK: declare hidden void @_ZN6test543fooINS_3zedEE3barEv
// CHECK-HIDDEN: declare hidden void @_ZN6test543fooINS_3zedEE3barEv
}
namespace test55 {
template <class T>
struct HIDDEN foo {
static void bar();
};
template <class T> struct foo;
void foobar() {
foo<int>::bar();
}
// CHECK: declare hidden void @_ZN6test553fooIiE3barEv
// CHECK-HIDDEN: declare hidden void @_ZN6test553fooIiE3barEv
}
namespace test56 {
template <class T> struct foo;
template <class T>
struct HIDDEN foo {
static void bar();
};
void foobar() {
foo<int>::bar();
}
// CHECK: declare hidden void @_ZN6test563fooIiE3barEv
// CHECK-HIDDEN: declare hidden void @_ZN6test563fooIiE3barEv
}
namespace test57 {
#pragma GCC visibility push(hidden)
template <class T>
struct foo;
void bar(foo<int>*);
template <class T>
struct foo {
static void zed();
};
void bah() {
foo<int>::zed();
}
#pragma GCC visibility pop
// CHECK: declare hidden void @_ZN6test573fooIiE3zedEv
// CHECK-HIDDEN: declare hidden void @_ZN6test573fooIiE3zedEv
}
namespace test58 {
#pragma GCC visibility push(hidden)
struct foo;
template<typename T>
struct DEFAULT bar {
static void zed() {
}
};
void bah() {
bar<foo>::zed();
}
#pragma GCC visibility pop
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test583barINS_3fooEE3zedEv
}
namespace test59 {
DEFAULT int f();
HIDDEN int g();
typedef int (*foo)();
template<foo x, foo y>
void test() {}
void use() {
test<&g, &f>();
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1gEvEEXadL_ZNS_1fEvEEEEvv
test<&f, &g>();
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test594testIXadL_ZNS_1fEvEEXadL_ZNS_1gEvEEEEvv
}
}
namespace test60 {
template<int i>
class HIDDEN a {};
template<int i>
class DEFAULT b {};
template<template<int> class x, template<int> class y>
void test() {}
void use() {
test<a, b>();
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1aENS_1bEEEvv
test<b, a>();
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
}
}
namespace test61 {
template <typename T1>
struct Class1
{
void f1() { f2(); }
inline void f2();
};
template<>
inline void Class1<int>::f2()
{
}
void g(Class1<int> *x) {
x->f1();
}
}
namespace test61 {
// Just test that we don't crash. Currently we apply this attribute. Current
// gcc issues a warning about it being unused since "the type is already
// defined". We should probably do the same.
template class HIDDEN Class1<int>;
}
namespace test62 {
template <typename T1>
struct Class1
{
void f1() { f2(); }
inline void f2() {}
};
template<>
inline void Class1<int>::f2()
{
}
void g(Class1<int> *x) {
x->f2();
}
}
namespace test62 {
template class HIDDEN Class1<int>;
// Just test that we don't crash. Currently we apply this attribute. Current
// gcc issues a warning about it being unused since "the type is already
// defined". We should probably do the same.
}
namespace test63 {
enum HIDDEN E { E0 };
struct A {
template <E> static void foo() {}
template <E> struct B {
static void foo() {}
};
};
void test() {
A::foo<E0>();
A::B<E0>::foo();
}
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv()
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv()
}
// Don't ignore the visibility of template arguments just because we
// explicitly instantiated something.
namespace test64 {
struct HIDDEN A {};
template <class P> struct B {
static DEFAULT void foo() {}
};
template class B<A>;
// CHECK-LABEL: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
}
namespace test65 {
class HIDDEN A {};
template <class T> struct B {
static void func();
template <class U> static void funcT1();
template <class U> static void funcT2();
class Inner {};
template <class U> class InnerT {};
};
template <template <class T> class Temp> struct C {
static void foo() {}
};
// CHECK-LABEL: define void @_ZN6test651BINS_1AEE4funcEv()
template <> DEFAULT void B<A>::func() {}
// CHECK-LABEL: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv()
template <> template <> DEFAULT void B<A>::funcT2<A>() {}
// CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv()
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv()
template <> template <class T> DEFAULT void B<A>::funcT1() {}
// CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv()
template <> struct DEFAULT B<A>::Inner {
static void foo() {}
};
// CHECK-LABEL: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv()
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv()
template <> template <class U> struct DEFAULT B<A>::InnerT {
static void foo() {}
};
void test() {
B<A>::funcT1<int>();
B<A>::funcT1<A>();
B<A>::Inner::foo();
B<A>::InnerT<int>::foo();
B<A>::InnerT<A>::foo();
}
template class C<B<A>::InnerT>;
}
namespace test66 {
template <typename T>
struct DEFAULT barT {
static void zed() {}
};
class foo;
class DEFAULT foo;
template struct barT<foo>;
// CHECK-LABEL: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
template <int* I>
struct DEFAULT barI {
static void zed() {}
};
extern int I;
extern int I DEFAULT;
template struct barI<&I>;
// CHECK-LABEL: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
typedef void (*fType)(void);
template<fType F>
struct DEFAULT barF {
static void zed() {}
};
void F();
void F() DEFAULT;
template struct barF<F>;
// CHECK-LABEL: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
}
namespace test67 {
template <typename T>
struct DEFAULT bar {
static void zed() {}
};
class foo;
class compute {
void f(foo *rootfoo);
};
class DEFAULT foo;
template struct bar<foo>;
// CHECK-LABEL: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
}
namespace test68 {
class A { public: ~A(); };
class f {
public:
f() {
static A test;
}
};
void g() {
f a;
}
// Check lines at top of file.
}
namespace test69 {
// PR18174
namespace foo {
void f();
}
namespace foo {
void f() {};
}
namespace foo __attribute__((visibility("hidden"))) {
}
// CHECK-LABEL: define void @_ZN6test693foo1fEv
// CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv
}
namespace test70 {
// Make sure both the vtable and VTT declarations are marked "hidden"
class HIDDEN A {
virtual void a();
};
class HIDDEN B : virtual A {
void a() override;
~B();
};
B::~B() {}
// Make sure both the vtable and VTT declarations are marked "hidden"
// when "-fvisibilty=hidden" is in use.
class C {};
class D : virtual C {};
D d;
// Check lines at top of file.
}
// https://github.com/llvm/llvm-project/issues/31462
namespace test71 {
template <class T>
struct foo {
static HIDDEN T zed();
template <class U> HIDDEN U bar();
};
template <class T>
T foo<T>::zed() { return {}; }
template <class T> template <class U>
U foo<T>::bar() { return {}; }
extern template struct DEFAULT foo<int>;
int use() {
foo<int> o;
foo<long> p;
return o.zed() + o.bar<int>() + p.zed() + p.bar<int>();
}
/// FIXME: foo<int>::bar is hidden in GCC w/ or w/o -fvisibility=hidden.
// CHECK-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv(
// CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v(
// CHECK-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv(
// CHECK-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v(
// CHECK-HIDDEN-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv(
// CHECK-HIDDEN-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v(
}
// https://github.com/llvm/llvm-project/issues/103477
namespace test72 {
template <class a>
struct t {
template <int>
static HIDDEN void bar() {}
};
void test() {
t<char>::bar<1>();
}
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test721tIcE3barILi1EEEvv(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test721tIcE3barILi1EEEvv(
}
// https://github.com/llvm/llvm-project/issues/31462
namespace test73 {
template <class T> struct s {
template <class U>
__attribute__((__visibility__("hidden"))) U should_not_be_exported();
};
template <class T> template <class U> U s<T>::should_not_be_exported() {
return U();
}
extern template struct __attribute__((__visibility__("default"))) s<int>;
int f() {
s<int> o;
return o.should_not_be_exported<int>();
}
// CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test731sIiE22should_not_be_exportedIiEET_v(
// CHECK-HIDDEN-LABEL: define linkonce_odr noundef i32 @_ZN6test731sIiE22should_not_be_exportedIiEET_v(
}
namespace test74 {
template <typename> struct T;
template <typename R>
struct T<void (R::*)()> {
template <typename M>
static __attribute__((__visibility__("hidden"))) void Invoke(M) {
}
};
struct C;
void (C::*MM)();
void Fun() {
T<decltype(MM)>::Invoke(0);
}
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test741TIMNS_1CEFvvEE6InvokeIiEEvT_(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test741TIMNS_1CEFvvEE6InvokeIiEEvT_(
}
namespace test75 {
template <class> struct T;
template <class C, class Ret>
struct T<Ret C::*> {
template <class M>
static __attribute__((__visibility__("hidden")))
void Invoke(M) {
}
};
struct A;
void Fun() {
T<void (A::*)()>::Invoke(0);
}
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test751TIMNS_1AEFvvEE6InvokeIiEEvT_(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test751TIMNS_1AEFvvEE6InvokeIiEEvT_(
}
#pragma clang attribute push([[gnu::visibility("hidden")]], apply_to=function)
namespace pragma_test {
struct S {
S();
};
S::S() = default;
// CHECK-LABEL: define hidden void @_ZN11pragma_test1SC2Ev(
// CHECK-HIDDEN-LABEL: define hidden void @_ZN11pragma_test1SC2Ev(
}
#pragma clang attribute pop
namespace no_pragma_test {
struct S {
S();
};
S::S() = default;
// CHECK-LABEL: define void @_ZN14no_pragma_test1SC2Ev(
// CHECK-HIDDEN-LABEL: define hidden void @_ZN14no_pragma_test1SC2Ev(
}