| // RUN: %clang_cc1 %s -emit-llvm -triple %itanium_abi_triple -std=c++11 -o - | FileCheck %s | 
 | // RUN: %clang_cc1 %s -emit-llvm -triple i686-linux-gnu -std=c++11 -o - | FileCheck %s | 
 | // RUN: %clang_cc1 %s -emit-llvm -triple x86_64-linux-gnu -std=c++11 -o - | FileCheck %s | 
 | // RUN: %clang_cc1 %s -emit-llvm -triple powerpc64le-unknown-linux-gnu -std=c++11 -o - | FileCheck %s | 
 |  | 
 | struct __attribute__((abi_tag("A", "B"))) A { }; | 
 |  | 
 | struct B: A { }; | 
 |  | 
 | template<class T> | 
 |  | 
 | struct C { | 
 | }; | 
 |  | 
 | struct D { A* p; }; | 
 |  | 
 | template<class T> | 
 | struct __attribute__((abi_tag("C", "D"))) E { | 
 | }; | 
 |  | 
 | struct __attribute__((abi_tag("A", "B"))) F { }; | 
 |  | 
 | A a1; | 
 | // CHECK-DAG: @_Z2a1B1AB1B = | 
 |  | 
 | __attribute__((abi_tag("C", "D"))) | 
 | A a2; | 
 | // CHECK-DAG: @_Z2a2B1AB1BB1CB1D = | 
 |  | 
 | B a3; | 
 | // CHECK-DAG: @a3 = | 
 |  | 
 | C<A> a4; | 
 | // CHECK-DAG: @_Z2a4B1AB1B = | 
 |  | 
 | D a5; | 
 | // CHECK-DAG: @a5 = | 
 |  | 
 | E<int> a6; | 
 | // CHECK-DAG: @_Z2a6B1CB1D = | 
 |  | 
 | E<A> a7; | 
 | // CHECK-DAG: @_Z2a7B1AB1BB1CB1D = | 
 |  | 
 | template<> | 
 | struct E<float> { | 
 |   static float a8; | 
 | }; | 
 | float E<float>::a8; | 
 | // CHECK-DAG: @_ZN1EB1CB1DIfE2a8E = | 
 |  | 
 | template<> | 
 | struct E<F> { | 
 |   static bool a9; | 
 | }; | 
 | bool E<F>::a9; | 
 | // CHECK-DAG: @_ZN1EB1CB1DI1FB1AB1BE2a9E = | 
 |  | 
 | struct __attribute__((abi_tag("A", "B"))) A10 { | 
 |   virtual ~A10() {} | 
 | } a10; | 
 | // vtable | 
 | // CHECK-DAG: @_ZTV3A10B1AB1B = | 
 | // typeinfo | 
 | // CHECK-DAG: @_ZTI3A10B1AB1B = | 
 |  | 
 | struct __attribute__((abi_tag("A"))) B11 { | 
 |   static A10 b; | 
 | }; | 
 | A10 B11::b; | 
 | // B11[abi:A]::b[abi:B] | 
 | // CHECK-DAG: @_ZN3B11B1A1bB1BE = | 
 |  | 
 | __attribute__ ((abi_tag("C", "D"))) | 
 | void* f1() { | 
 |   return 0; | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f1B1CB1Dv( | 
 |  | 
 | __attribute__ ((abi_tag("C", "D"))) | 
 | A* f2() { | 
 |   return 0; | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f2B1AB1BB1CB1Dv( | 
 |  | 
 | B* f3() { | 
 |   return 0; | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f3v( | 
 |  | 
 | C<A>* f4() { | 
 |   return 0; | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f4B1AB1Bv( | 
 |  | 
 | D* f5() { | 
 |   return 0; | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f5v( | 
 |  | 
 | E<char>* f6() { | 
 |   return 0; | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f6B1CB1Dv( | 
 |  | 
 | E<A>* f7() { | 
 |   return 0; | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f7B1AB1BB1CB1Dv( | 
 |  | 
 | void f8(E<A>*) { | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_Z2f8P1EB1CB1DI1AB1AB1BE( | 
 |  | 
 | inline namespace Names1 __attribute__((__abi_tag__)) { | 
 |     class C1 {}; | 
 | } | 
 | C1 f9() { return C1(); } | 
 | // CHECK-DAG: @_Z2f9B6Names1v( | 
 |  | 
 | inline namespace Names2 __attribute__((__abi_tag__("Tag1", "Tag2"))) { | 
 |     class C2 {}; | 
 | } | 
 | C2 f10() { return C2(); } | 
 | // CHECK-DAG: @_Z3f10B4Tag1B4Tag2v( | 
 |  | 
 | void __attribute__((abi_tag("A"))) f11(A) {} | 
 | // f11[abi:A](A[abi:A][abi:B]) | 
 | // CHECK-DAG: define {{.*}} @_Z3f11B1A1AB1AB1B( | 
 |  | 
 | A f12(A) { return A(); } | 
 | // f12(A[abi:A][abi:B]) | 
 | // CHECK-DAG: define {{.*}} @_Z3f121AB1AB1B( | 
 |  | 
 | inline void f13() { | 
 |   struct L { | 
 |     static E<int>* foo() { | 
 |       static A10 a; | 
 |       return 0; | 
 |     } | 
 |   }; | 
 |   L::foo(); | 
 | } | 
 | void f13_test() { | 
 |   f13(); | 
 | } | 
 | // f13()::L::foo[abi:C][abi:D]() | 
 | // CHECK-DAG: define linkonce_odr {{(dso_local )?}}%struct.E* @_ZZ3f13vEN1L3fooB1CB1DEv( | 
 |  | 
 | // f13()::L::foo[abi:C][abi:D]()::a[abi:A][abi:B] | 
 | // CHECK-DAG: @_ZZZ3f13vEN1L3fooB1CB1DEvE1aB1AB1B = | 
 |  | 
 | // guard variable for f13()::L::foo[abi:C][abi:D]()::a[abi:A][abi:B] | 
 | // CHECK-DAG: @_ZGVZZ3f13vEN1L3fooB1CB1DEvE1aB1AB1B = | 
 |  | 
 | struct __attribute__((abi_tag("TAG"))) A14 { | 
 |   A14 f14(); | 
 | }; | 
 | A14 A14::f14() { | 
 |   return A14(); | 
 | } | 
 | // A14[abi:TAG]::f14() | 
 | // CHECK-DAG: define {{.+}} @_ZN3A14B3TAG3f14Ev( | 
 |  | 
 | template<class T> | 
 | T f15() { | 
 |   return T(); | 
 | } | 
 | void f15_test() { | 
 |   f15<A14>(); | 
 | } | 
 | // A14[abi:TAG] f15<A14[abi:TAG]>() | 
 | // CHECK-DAG: define linkonce_odr {{.+}} @_Z3f15I3A14B3TAGET_v( | 
 |  | 
 | template<class T> | 
 | A14 f16() { | 
 |   return A14(); | 
 | } | 
 | void f16_test() { | 
 |   f16<int>(); | 
 | } | 
 | // A14[abi:TAG] f16<int>() | 
 | // CHECK-DAG: define linkonce_odr {{.+}} @_Z3f16IiE3A14B3TAGv( | 
 |  | 
 | template<class T> | 
 | struct __attribute__((abi_tag("TAG"))) A17 { | 
 |   A17 operator+(const A17& a) { | 
 |     return a; | 
 |   } | 
 | }; | 
 | void f17_test() { | 
 |   A17<int> a, b; | 
 |   a + b; | 
 | } | 
 | // A17[abi:TAG]<int>::operator+(A17[abi:TAG]<int> const&) | 
 | // CHECK-DAG: define linkonce_odr {{.+}} @_ZN3A17B3TAGIiEplERKS0_( | 
 |  | 
 | struct A18 { | 
 |   operator A() { return A(); } | 
 | }; | 
 | void f18_test() { | 
 |   A a = A18(); | 
 | } | 
 | // A18::operator A[abi:A][abi:B]() but GCC adds the same tags twice! | 
 | // CHECK-DAG: define linkonce_odr {{.+}} @_ZN3A18cv1AB1AB1BEv( | 
 |  | 
 | namespace N19 { | 
 |   class A {}; | 
 |   class __attribute__((abi_tag("B"))) B {}; | 
 |   class D {}; | 
 |   class F {}; | 
 |  | 
 |   template<typename T, B F(T, D)> | 
 |   class C {}; | 
 |  | 
 |   B foo(A, D); | 
 | } | 
 | void f19_test(N19::C<N19::A,  &N19::foo>, N19::F, N19::D) { | 
 | } | 
 | // f19_test(N19::C<N19::A, &N19::foo[abi:B]>, N19::F, N19::D) | 
 | // CHECK-DAG: define {{(dso_local )?}}void @_Z8f19_testN3N191CINS_1AEXadL_ZNS_3fooB1BES1_NS_1DEEEEENS_1FES2_( | 
 |  | 
 | namespace pr30440 { | 
 |  | 
 | template<class F> void g(F); | 
 | template<class ...A> auto h(A ...a)->decltype (g (0, g < a > (a) ...)) { | 
 | } | 
 | // CHECK-DAG: define {{.*}} @_ZN7pr304401hIJEEEDTcl1gLi0Espcl1gIL_ZZNS_1hEDpT_E1aEEfp_EEES2_( | 
 |  | 
 | void pr30440_test () { | 
 |   h(); | 
 | } | 
 |  | 
 | } |