1*dbc96b51SFangrui Song // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -O0 -o - %s | FileCheck %s
2d269579aSLouis Dionne 
3d269579aSLouis Dionne // Test that we do not assume that entities marked with the
4d269579aSLouis Dionne // exclude_from_explicit_instantiation attribute are instantiated
5d269579aSLouis Dionne // in another TU when an extern template instantiation declaration
6d269579aSLouis Dionne // is present. We test that by making sure that definitions are
7d269579aSLouis Dionne // generated in this TU despite there being an extern template
8d269579aSLouis Dionne // instantiation declaration, which is normally not the case.
9d269579aSLouis Dionne 
10d269579aSLouis Dionne #define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation))
11d269579aSLouis Dionne 
12d269579aSLouis Dionne template <class T>
13d269579aSLouis Dionne struct Foo {
14d269579aSLouis Dionne   EXCLUDE_FROM_EXPLICIT_INSTANTIATION        inline void non_static_member_function1();
15d269579aSLouis Dionne   EXCLUDE_FROM_EXPLICIT_INSTANTIATION               void non_static_member_function2();
16d269579aSLouis Dionne 
17d269579aSLouis Dionne   EXCLUDE_FROM_EXPLICIT_INSTANTIATION static inline void static_member_function1();
18d269579aSLouis Dionne   EXCLUDE_FROM_EXPLICIT_INSTANTIATION static        void static_member_function2();
19d269579aSLouis Dionne 
20d269579aSLouis Dionne   EXCLUDE_FROM_EXPLICIT_INSTANTIATION static        int static_data_member;
21d269579aSLouis Dionne 
22d269579aSLouis Dionne   struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION member_class1 {
static_member_functionFoo::member_class123d269579aSLouis Dionne     static void static_member_function() { }
24d269579aSLouis Dionne   };
25d269579aSLouis Dionne 
26d269579aSLouis Dionne   struct member_class2 {
static_member_functionFoo::member_class227d269579aSLouis Dionne     EXCLUDE_FROM_EXPLICIT_INSTANTIATION static void static_member_function() { }
28d269579aSLouis Dionne   };
29d269579aSLouis Dionne };
30d269579aSLouis Dionne 
non_static_member_function1()31d269579aSLouis Dionne template <class T> inline void Foo<T>::non_static_member_function1() { }
non_static_member_function2()32d269579aSLouis Dionne template <class T>        void Foo<T>::non_static_member_function2() { }
33d269579aSLouis Dionne 
static_member_function1()34d269579aSLouis Dionne template <class T> inline void Foo<T>::static_member_function1() { }
static_member_function2()35d269579aSLouis Dionne template <class T>        void Foo<T>::static_member_function2() { }
36d269579aSLouis Dionne 
37d269579aSLouis Dionne template <class T>        int Foo<T>::static_data_member = 0;
38d269579aSLouis Dionne 
39d269579aSLouis Dionne extern template struct Foo<int>;
40d269579aSLouis Dionne 
use()41d269579aSLouis Dionne void use() {
42d269579aSLouis Dionne   Foo<int> f;
43d269579aSLouis Dionne 
44d269579aSLouis Dionne   // An inline non-static member function marked with the attribute is not
45d269579aSLouis Dionne   // part of the extern template declaration, so a definition must be emitted
46d269579aSLouis Dionne   // in this TU.
47*dbc96b51SFangrui Song   // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE27non_static_member_function1Ev
48d269579aSLouis Dionne   f.non_static_member_function1();
49d269579aSLouis Dionne 
50d269579aSLouis Dionne   // A non-inline non-static member function marked with the attribute is
51d269579aSLouis Dionne   // not part of the extern template declaration, so a definition must be
52d269579aSLouis Dionne   // emitted in this TU.
53*dbc96b51SFangrui Song   // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE27non_static_member_function2Ev
54d269579aSLouis Dionne   f.non_static_member_function2();
55d269579aSLouis Dionne 
56d269579aSLouis Dionne   // An inline static member function marked with the attribute is not
57d269579aSLouis Dionne   // part of the extern template declaration, so a definition must be
58d269579aSLouis Dionne   // emitted in this TU.
59*dbc96b51SFangrui Song   // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE23static_member_function1Ev
60d269579aSLouis Dionne   Foo<int>::static_member_function1();
61d269579aSLouis Dionne 
62d269579aSLouis Dionne   // A non-inline static member function marked with the attribute is not
63d269579aSLouis Dionne   // part of the extern template declaration, so a definition must be
64d269579aSLouis Dionne   // emitted in this TU.
65*dbc96b51SFangrui Song   // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE23static_member_function2Ev
66d269579aSLouis Dionne   Foo<int>::static_member_function2();
67d269579aSLouis Dionne 
68d269579aSLouis Dionne   // A static data member marked with the attribute is not part of the
69d269579aSLouis Dionne   // extern template declaration, so a definition must be emitted in this TU.
70d269579aSLouis Dionne   // CHECK-DAG: @_ZN3FooIiE18static_data_memberE = linkonce_odr global
71d269579aSLouis Dionne   int& odr_use = Foo<int>::static_data_member;
72d269579aSLouis Dionne 
73d269579aSLouis Dionne   // A member class marked with the attribute is not part of the extern
74d269579aSLouis Dionne   // template declaration (it is not recursively instantiated), so its member
75d269579aSLouis Dionne   // functions must be emitted in this TU.
76d269579aSLouis Dionne   // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE13member_class122static_member_functionEv
77d269579aSLouis Dionne   Foo<int>::member_class1::static_member_function();
78d269579aSLouis Dionne 
79d269579aSLouis Dionne   // A member function marked with the attribute in a member class is not
80d269579aSLouis Dionne   // part of the extern template declaration of the parent class template, so
81d269579aSLouis Dionne   // it must be emitted in this TU.
82d269579aSLouis Dionne   // CHECK-DAG: define linkonce_odr void @_ZN3FooIiE13member_class222static_member_functionEv
83d269579aSLouis Dionne   Foo<int>::member_class2::static_member_function();
84d269579aSLouis Dionne }
85