diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2013-06-10 20:45:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2013-06-10 20:45:12 +0000 |
commit | 6a0372513edbc473b538d2f724efac50405d6fef (patch) | |
tree | 8f7776b7310bebaf415ac5b69e46e9f928c37144 /test/CodeGenCXX | |
parent | 809500fc2c13c8173a16b052304d983864e4a1e1 (diff) |
Notes
Diffstat (limited to 'test/CodeGenCXX')
20 files changed, 1031 insertions, 22 deletions
diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp index 8d9fce040fd7f..d683493a83d81 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -51,6 +51,12 @@ struct wantslist1 { // CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, i32 0, i32 0), i{{32|64}} 3 } std::initializer_list<int> globalInitList1 = {1, 2, 3}; +namespace thread_local_global_array { + // CHECK: @_ZN25thread_local_global_arrayL11x__initlistE = internal thread_local global [4 x i32] [i32 1, i32 2, i32 3, i32 4] + // CHECK: @_ZN25thread_local_global_array1xE = thread_local global {{.*}} @_ZN25thread_local_global_arrayL11x__initlistE, {{.*}} i64 4 + std::initializer_list<int> thread_local x = { 1, 2, 3, 4 }; +} + // CHECK: @_ZL25globalInitList2__initlist = internal global [2 x %{{[^ ]*}}] zeroinitializer // CHECK: @globalInitList2 = global %{{[^ ]+}} { %[[WITHARG:[^ *]+]]* getelementptr inbounds ([2 x // CHECK: appending global @@ -250,3 +256,22 @@ namespace PR12178 { map m{ {1, 2}, {3, 4} }; } + +namespace rdar13325066 { + struct X { ~X(); }; + + // CHECK: define void @_ZN12rdar133250664loopERNS_1XES1_ + void loop(X &x1, X &x2) { + // CHECK: br label + // CHECK: br i1 + // CHECK: br label + // CHECK call void @_ZN12rdar133250661XD1Ev + // CHECK: br label + // CHECK: br label + // CHECK: call void @_ZN12rdar133250661XD1Ev + // CHECK: br i1 + // CHECK: br label + // CHECK: ret void + for (X x : { x1, x2 }) { } + } +} diff --git a/test/CodeGenCXX/cxx11-thread-local-reference.cpp b/test/CodeGenCXX/cxx11-thread-local-reference.cpp new file mode 100644 index 0000000000000..2ea9acda48153 --- /dev/null +++ b/test/CodeGenCXX/cxx11-thread-local-reference.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s + +int &f(); + +// CHECK: @r = thread_local global i32* null +thread_local int &r = f(); + +// CHECK: @_ZTH1r = alias void ()* @__tls_init + +int &g() { return r; } + +// CHECK: define {{.*}} @[[R_INIT:.*]]() +// CHECK: call i32* @_Z1fv() +// CHECK: store i32* %{{.*}}, i32** @r, align 8 + +// CHECK: define i32* @_Z1gv() +// CHECK: call i32* @_ZTW1r() +// CHECK: ret i32* %{{.*}} + +// CHECK: define weak_odr hidden i32* @_ZTW1r() { +// CHECK: call void @_ZTH1r() +// CHECK: load i32** @r, align 8 +// CHECK: ret i32* %{{.*}} + +// CHECK: define internal void @__tls_init() +// CHECK: call void @[[R_INIT]]() diff --git a/test/CodeGenCXX/cxx11-thread-local.cpp b/test/CodeGenCXX/cxx11-thread-local.cpp new file mode 100644 index 0000000000000..a7141d133bbe3 --- /dev/null +++ b/test/CodeGenCXX/cxx11-thread-local.cpp @@ -0,0 +1,173 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s + +int f(); +int g(); + +// CHECK: @a = thread_local global i32 0 +thread_local int a = f(); +extern thread_local int b; +// CHECK: @c = global i32 0 +int c = b; +// CHECK: @_ZL1d = internal thread_local global i32 0 +static thread_local int d = g(); + +struct U { static thread_local int m; }; +// CHECK: @_ZN1U1mE = thread_local global i32 0 +thread_local int U::m = f(); + +template<typename T> struct V { static thread_local int m; }; +template<typename T> thread_local int V<T>::m = g(); + +// CHECK: @e = global i32 0 +int e = V<int>::m; + +// CHECK: @_ZN1VIiE1mE = weak_odr thread_local global i32 0 + +// CHECK: @_ZZ1fvE1n = internal thread_local global i32 0 + +// CHECK: @_ZGVZ1fvE1n = internal thread_local global i8 0 + +// CHECK: @_ZZ8tls_dtorvE1s = internal thread_local global +// CHECK: @_ZGVZ8tls_dtorvE1s = internal thread_local global i8 0 + +// CHECK: @_ZZ8tls_dtorvE1t = internal thread_local global +// CHECK: @_ZGVZ8tls_dtorvE1t = internal thread_local global i8 0 + +// CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global +// CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0 +// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global + +// CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0 + +// CHECK: @__tls_guard = internal thread_local global i8 0 + +// CHECK: @llvm.global_ctors = appending global {{.*}} @[[GLOBAL_INIT:[^ ]*]] + +// CHECK: @_ZTH1a = alias void ()* @__tls_init +// CHECK: @_ZTHL1d = alias internal void ()* @__tls_init +// CHECK: @_ZTHN1U1mE = alias void ()* @__tls_init +// CHECK: @_ZTHN1VIiE1mE = alias weak_odr void ()* @__tls_init + + +// Individual variable initialization functions: + +// CHECK: define {{.*}} @[[A_INIT:.*]]() +// CHECK: call i32 @_Z1fv() +// CHECK-NEXT: store i32 {{.*}}, i32* @a, align 4 + +// CHECK: define i32 @_Z1fv() +int f() { + // CHECK: %[[GUARD:.*]] = load i8* @_ZGVZ1fvE1n, align 1 + // CHECK: %[[NEED_INIT:.*]] = icmp eq i8 %[[GUARD]], 0 + // CHECK: br i1 %[[NEED_INIT]] + + // CHECK: %[[CALL:.*]] = call i32 @_Z1gv() + // CHECK: store i32 %[[CALL]], i32* @_ZZ1fvE1n, align 4 + // CHECK: store i8 1, i8* @_ZGVZ1fvE1n + // CHECK: br label + static thread_local int n = g(); + + // CHECK: load i32* @_ZZ1fvE1n, align 4 + return n; +} + +// CHECK: define {{.*}} @[[C_INIT:.*]]() +// CHECK: call i32* @_ZTW1b() +// CHECK-NEXT: load i32* %{{.*}}, align 4 +// CHECK-NEXT: store i32 %{{.*}}, i32* @c, align 4 + +// CHECK: define weak_odr hidden i32* @_ZTW1b() +// CHECK: br i1 icmp ne (void ()* @_ZTH1b, void ()* null), +// not null: +// CHECK: call void @_ZTH1b() +// CHECK: br label +// finally: +// CHECK: ret i32* @b + +// CHECK: define {{.*}} @[[D_INIT:.*]]() +// CHECK: call i32 @_Z1gv() +// CHECK-NEXT: store i32 %{{.*}}, i32* @_ZL1d, align 4 + +// CHECK: define {{.*}} @[[U_M_INIT:.*]]() +// CHECK: call i32 @_Z1fv() +// CHECK-NEXT: store i32 %{{.*}}, i32* @_ZN1U1mE, align 4 + +// CHECK: define {{.*}} @[[E_INIT:.*]]() +// CHECK: call i32* @_ZTWN1VIiE1mE() +// CHECK-NEXT: load i32* %{{.*}}, align 4 +// CHECK-NEXT: store i32 %{{.*}}, i32* @e, align 4 + +// CHECK: define weak_odr hidden i32* @_ZTWN1VIiE1mE() +// CHECK: call void @_ZTHN1VIiE1mE() +// CHECK: ret i32* @_ZN1VIiE1mE + + +struct S { S(); ~S(); }; +struct T { ~T(); }; + +// CHECK: define void @_Z8tls_dtorv() +void tls_dtor() { + // CHECK: load i8* @_ZGVZ8tls_dtorvE1s + // CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZZ8tls_dtorvE1s) + // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZZ8tls_dtorvE1s{{.*}} @__dso_handle + // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1s + static thread_local S s; + + // CHECK: load i8* @_ZGVZ8tls_dtorvE1t + // CHECK-NOT: _ZN1T + // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1TD1Ev {{.*}}@_ZZ8tls_dtorvE1t{{.*}} @__dso_handle + // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1t + static thread_local T t; + + // CHECK: load i8* @_ZGVZ8tls_dtorvE1u + // CHECK: call void @_ZN1SC1Ev(%struct.S* @_ZGRZ8tls_dtorvE1u) + // CHECK: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZGRZ8tls_dtorvE1u{{.*}} @__dso_handle + // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1u + static thread_local const S &u = S(); +} + +// CHECK: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*) + +// CHECK: define {{.*}} @[[V_M_INIT:.*]]() +// CHECK: load i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*) +// CHECK: %[[V_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0 +// CHECK: br i1 %[[V_M_INITIALIZED]], +// need init: +// CHECK: call i32 @_Z1gv() +// CHECK: store i32 %{{.*}}, i32* @_ZN1VIiE1mE, align 4 +// CHECK: store i64 1, i64* @_ZGVN1VIiE1mE +// CHECK: br label + +// CHECK: define {{.*}}@[[GLOBAL_INIT:.*]]() +// CHECK: call void @[[C_INIT]]() +// CHECK: call void @[[E_INIT]]() + + +// CHECK: define {{.*}}@__tls_init() +// CHECK: load i8* @__tls_guard +// CHECK: %[[NEED_TLS_INIT:.*]] = icmp eq i8 %{{.*}}, 0 +// CHECK: store i8 1, i8* @__tls_guard +// CHECK: br i1 %[[NEED_TLS_INIT]], +// init: +// CHECK: call void @[[A_INIT]]() +// CHECK: call void @[[D_INIT]]() +// CHECK: call void @[[U_M_INIT]]() +// CHECK: call void @[[V_M_INIT]]() + + +// CHECK: define weak_odr hidden i32* @_ZTW1a() { +// CHECK: call void @_ZTH1a() +// CHECK: ret i32* @a +// CHECK: } + + +// CHECK: declare extern_weak void @_ZTH1b() + + +// CHECK: define internal hidden i32* @_ZTWL1d() +// CHECK: call void @_ZTHL1d() +// CHECK: ret i32* @_ZL1d + +// CHECK: define weak_odr hidden i32* @_ZTWN1U1mE() +// CHECK: call void @_ZTHN1U1mE() +// CHECK: ret i32* @_ZN1U1mE diff --git a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp new file mode 100644 index 0000000000000..ef78c434e35e3 --- /dev/null +++ b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -std=c++1y %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s + +struct A { + int n = 0; + const char *p; + char k = p[n]; + int f(); + int x = f(); + union { + char c; + double d = 1.0; + }; +}; + +int f(); + +union B { + int a; + int f(); + int b = f(); +}; + +A a { .p = "foobar" }; +A b { 4, "bazquux", .x = 42, .c = 9 }; +A c { 1, 0, 'A', f(), { 3 } }; + +// CHECK: @[[STR_A:.*]] = {{.*}} [7 x i8] c"foobar\00" +// CHECK: @[[STR_B:.*]] = {{.*}} [8 x i8] c"bazquux\00" + +B x; +B y {}; +B z { 1 }; +// CHECK: @z = global {{.*}} { i32 1 } + +// Initialization of 'a': + +// CHECK: store i32 0, i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0) +// CHECK: store i8* {{.*}} @[[STR_A]]{{.*}}, i8** getelementptr inbounds ({{.*}} @a, i32 0, i32 1) +// CHECK: load i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0) +// CHECK: load i8** getelementptr inbounds ({{.*}} @a, i32 0, i32 1) +// CHECK: getelementptr inbounds i8* %{{.*}}, {{.*}} %{{.*}} +// CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @a, i32 0, i32 2) +// CHECK: call i32 @_ZN1A1fEv({{.*}} @a) +// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @a, i32 0, i32 3) +// CHECK: call void @{{.*}}C1Ev({{.*}} getelementptr inbounds (%struct.A* @a, i32 0, i32 4)) + +// Initialization of 'b': + +// CHECK: store i32 4, i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0) +// CHECK: store i8* {{.*}} @[[STR_B]]{{.*}}, i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1) +// CHECK: load i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0) +// CHECK: load i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1) +// CHECK: getelementptr inbounds i8* %{{.*}}, {{.*}} %{{.*}} +// CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @b, i32 0, i32 2) +// CHECK-NOT: @_ZN1A1fEv +// CHECK: store i32 42, i32* getelementptr inbounds ({{.*}}* @b, i32 0, i32 3) +// CHECK-NOT: C1Ev +// CHECK: store i8 9, i8* {{.*}} @b, i32 0, i32 4) + +// Initialization of 'c': + +// CHECK: store i32 1, i32* getelementptr inbounds ({{.*}} @c, i32 0, i32 0) +// CHECK: store i8* null, i8** getelementptr inbounds ({{.*}} @c, i32 0, i32 1) +// CHECK-NOT: load +// CHECK: store i8 65, i8* getelementptr inbounds ({{.*}} @c, i32 0, i32 2) +// CHECK: call i32 @_Z1fv() +// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @c, i32 0, i32 3) +// CHECK-NOT: C1Ev +// CHECK: store i8 3, i8* {{.*}} @c, i32 0, i32 4) + +// CHECK: call void @_ZN1BC1Ev({{.*}} @x) + +// CHECK: call i32 @_ZN1B1fEv({{.*}} @y) +// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}} @y, i32 0, i32 0) diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp index 262e996d44d7d..13a7914b7be0b 100644 --- a/test/CodeGenCXX/debug-info-namespace.cpp +++ b/test/CodeGenCXX/debug-info-namespace.cpp @@ -5,13 +5,33 @@ namespace A { namespace B { int i; } +using namespace B; } +using namespace A; + +int func(bool b) { + if (b) { + using namespace A::B; + return i; + } + using namespace A; + return B::i; +} + +// CHECK: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !""} ; [ DW_TAG_compile_unit ] // CHECK: [[FILE:![0-9]*]] {{.*}}debug-info-namespace.cpp" +// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 9] [def] [func] +// CHECK: [[FILE2:![0-9]*]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp] // CHECK: [[VAR:![0-9]*]] = {{.*}}, metadata [[NS:![0-9]*]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i] -// CHECK: [[NS]] = {{.*}}, metadata [[FILE2:![0-9]*]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1] +// CHECK: [[NS]] = {{.*}}, metadata [[FILE2]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1] // CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 3] -// CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp] +// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]]} +// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 4} ; [ DW_TAG_imported_module ] +// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 7} ; [ DW_TAG_imported_module ] +// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX:![0-9]*]], metadata [[NS]], i32 11} ; [ DW_TAG_imported_module ] +// CHECK: [[LEX]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 10, i32 0, i32 0} ; [ DW_TAG_lexical_block ] +// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 14} ; [ DW_TAG_imported_module ] // FIXME: It is confused on win32 to generate file entry when dosish filename is given. // REQUIRES: shell diff --git a/test/CodeGenCXX/extern-c.cpp b/test/CodeGenCXX/extern-c.cpp index a8c4f0cdbd30f..5899b9348c5a3 100644 --- a/test/CodeGenCXX/extern-c.cpp +++ b/test/CodeGenCXX/extern-c.cpp @@ -36,3 +36,30 @@ namespace test2 { extern "C" X test2_b; X test2_b; } + +extern "C" { + static int unused_var; + static int unused_fn() { return 0; } + + __attribute__((used)) static int internal_var; + __attribute__((used)) static int internal_fn() { return 0; } + + __attribute__((used)) static int duplicate_internal_var; + __attribute__((used)) static int duplicate_internal_fn() { return 0; } + + namespace N { + __attribute__((used)) static int duplicate_internal_var; + __attribute__((used)) static int duplicate_internal_fn() { return 0; } + } + + // CHECK: @llvm.used = appending global {{.*}} @internal_var {{.*}} @internal_fn + + // CHECK-NOT: @unused + // CHECK-NOT: @duplicate_internal + // CHECK: @internal_var = alias internal i32* @_Z12internal_var + // CHECK-NOT: @unused + // CHECK-NOT: @duplicate_internal + // CHECK: @internal_fn = alias internal i32 ()* @_Z11internal_fnv + // CHECK-NOT: @unused + // CHECK-NOT: @duplicate_internal +} diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp index adb9f6dc1a7bd..0f39784929763 100644 --- a/test/CodeGenCXX/inheriting-constructor.cpp +++ b/test/CodeGenCXX/inheriting-constructor.cpp @@ -7,6 +7,10 @@ B::~B() {} B b(123); +struct C { template<typename T> C(T); }; +struct D : C { using C::C; }; +D d(123); + // CHECK: define void @_ZN1BD0Ev // CHECK: define void @_ZN1BD1Ev // CHECK: define void @_ZN1BD2Ev @@ -14,5 +18,11 @@ B b(123); // CHECK: define linkonce_odr void @_ZN1BC1Ei( // CHECK: call void @_ZN1BC2Ei( +// CHECK: define linkonce_odr void @_ZN1DC1IiEET_( +// CHECK: call void @_ZN1DC2IiEET_( + +// CHECK: define linkonce_odr void @_ZN1DC2IiEET_( +// CHECK: call void @_ZN1CC2IiEET_( + // CHECK: define linkonce_odr void @_ZN1BC2Ei( // CHECK: call void @_ZN1AC2Ei( diff --git a/test/CodeGenCXX/linetable-cleanup.cpp b/test/CodeGenCXX/linetable-cleanup.cpp new file mode 100644 index 0000000000000..4077af6d8e012 --- /dev/null +++ b/test/CodeGenCXX/linetable-cleanup.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s + +// Check the line numbers for cleanup code with EH in combinatin with +// simple return expressions. + +// CHECK: define {{.*}}foo +// CHECK: call void @_ZN1CD1Ev(%class.C* {{.*}}), !dbg ![[CLEANUP:[0-9]+]] +// CHECK: ret i32 0, !dbg ![[RET:[0-9]+]] + +class C { +public: + ~C() {} + int i; +}; + +int foo() +{ + C c; + c.i = 42; + // This breakpoint should be at/before the cleanup code. + // CHECK: ![[CLEANUP]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} + return 0; + // CHECK: ![[RET]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null} +} diff --git a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp index 0ac9b3f121f33..d03ba52649757 100644 --- a/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ms-arg-qualifiers.cpp @@ -60,6 +60,51 @@ void foo_pcrbd(const char * volatile* x) {} void foo_pcrcd(volatile char * volatile* x) {} // CHECK: "\01?foo_pcrcd@@YAXPCRCD@Z" +void foo_aad(char &x) {} +// CHECK: "\01?foo_aad@@YAXAAD@Z" + +void foo_abd(const char &x) {} +// CHECK: "\01?foo_abd@@YAXABD@Z" + +void foo_aapad(char *&x) {} +// CHECK: "\01?foo_aapad@@YAXAAPAD@Z" + +void foo_aapbd(const char *&x) {} +// CHECK: "\01?foo_aapbd@@YAXAAPBD@Z" + +void foo_abqad(char * const &x) {} +// CHECK: "\01?foo_abqad@@YAXABQAD@Z" + +void foo_abqbd(const char * const &x) {} +// CHECK: "\01?foo_abqbd@@YAXABQBD@Z" + +void foo_aay144h(int (&x)[5][5]) {} +// CHECK: "\01?foo_aay144h@@YAXAAY144H@Z" + +void foo_aay144cbh(const int (&x)[5][5]) {} +// CHECK: "\01?foo_aay144cbh@@YAXAAY144$$CBH@Z" + +void foo_qay144h(int (&&x)[5][5]) {} +// CHECK: "\01?foo_qay144h@@YAX$$QAY144H@Z" + +void foo_qay144cbh(const int (&&x)[5][5]) {} +// CHECK: "\01?foo_qay144cbh@@YAX$$QAY144$$CBH@Z" + +void foo_p6ahxz(int x()) {} +// CHECK: "\01?foo_p6ahxz@@YAXP6AHXZ@Z" + +void foo_a6ahxz(int (&x)()) {} +// CHECK: "\01?foo_a6ahxz@@YAXA6AHXZ@Z" + +void foo_q6ahxz(int (&&x)()) {} +// CHECK: "\01?foo_q6ahxz@@YAX$$Q6AHXZ@Z" + +void foo_qay04h(int x[5][5]) {} +// CHECK: "\01?foo_qay04h@@YAXQAY04H@Z" + +void foo_qay04cbh(const int x[5][5]) {} +// CHECK: "\01?foo_qay04cbh@@YAXQAY04$$CBH@Z" + typedef double Vector[3]; void foo(Vector*) {} diff --git a/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp index 63bc4a9eb3c66..87e04c645eced 100644 --- a/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp +++ b/test/CodeGenCXX/mangle-ms-return-qualifiers.cpp @@ -155,6 +155,15 @@ const volatile struct S* f5() { return 0; } struct S& f6() { return *(struct S*)0; } // CHECK: "\01?f6@@YAAAUS@@XZ" +struct S* const f7() { return 0; } +// CHECK: "\01?f7@@YAQAUS@@XZ" + +int S::* f8() { return 0; } +// CHECK: "\01?f8@@YAPQS@@HXZ" + +int S::* const f9() { return 0; } +// CHECK: "\01?f9@@YAQQS@@HXZ" + typedef int (*function_pointer)(int); function_pointer g1() { return 0; } diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp index d0e8af48884a2..10e68248dc18a 100644 --- a/test/CodeGenCXX/mangle-ms-templates.cpp +++ b/test/CodeGenCXX/mangle-ms-templates.cpp @@ -3,7 +3,7 @@ template<typename T> class Class { public: - void method() {} + Class() {} }; class Typename { }; @@ -32,12 +32,30 @@ class BoolTemplate<true> { void template_mangling() { Class<Typename> c1; - c1.method(); -// CHECK: call {{.*}} @"\01?method@?$Class@VTypename@@@@QAEXXZ" +// CHECK: call {{.*}} @"\01??0?$Class@VTypename@@@@QAE@XZ" + + Class<const Typename> c1_const; +// CHECK: call {{.*}} @"\01??0?$Class@$$CBVTypename@@@@QAE@XZ" + Class<volatile Typename> c1_volatile; +// CHECK: call {{.*}} @"\01??0?$Class@$$CCVTypename@@@@QAE@XZ" + Class<const volatile Typename> c1_cv; +// CHECK: call {{.*}} @"\01??0?$Class@$$CDVTypename@@@@QAE@XZ" Class<Nested<Typename> > c2; - c2.method(); -// CHECK: call {{.*}} @"\01?method@?$Class@V?$Nested@VTypename@@@@@@QAEXXZ" +// CHECK: call {{.*}} @"\01??0?$Class@V?$Nested@VTypename@@@@@@QAE@XZ" + + Class<int * const> c_intpc; +// CHECK: call {{.*}} @"\01??0?$Class@QAH@@QAE@XZ" + Class<int()> c_ft; +// CHECK: call {{.*}} @"\01??0?$Class@$$A6AHXZ@@QAE@XZ" + Class<int[]> c_inti; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY0A@H@@QAE@XZ" + Class<int[5]> c_int5; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY04H@@QAE@XZ" + Class<const int[5]> c_intc5; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY04$$CBH@@QAE@XZ" + Class<int * const[5]> c_intpc5; +// CHECK: call {{.*}} @"\01??0?$Class@$$BY04QAH@@QAE@XZ" BoolTemplate<false> _false; // CHECK: call {{.*}} @"\01??0?$BoolTemplate@$0A@@@QAE@XZ" diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp index 6441d67a758a0..1b98a84823f41 100644 --- a/test/CodeGenCXX/mangle-ms.cpp +++ b/test/CodeGenCXX/mangle-ms.cpp @@ -17,11 +17,8 @@ // CHECK: @"\01?l@@3P8foo@@AEHH@ZA" // CHECK: @"\01?color1@@3PANA" // CHECK: @"\01?color2@@3QBNB" - -// FIXME: The following three tests currently fail, see http://llvm.org/PR13182 -// Replace "CHECK-NOT" with "CHECK" when it is fixed. -// CHECK-NOT: @"\01?color3@@3QAY02$$CBNA" -// CHECK-NOT: @"\01?color4@@3QAY02$$CBNA" +// CHECK: @"\01?color3@@3QAY02$$CBNA" +// CHECK: @"\01?color4@@3QAY02$$CBNA" int a; diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp index 997e007086ccc..3fffc9d72cb10 100755 --- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -1,10 +1,110 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct B1 { + void foo(); + int b; +}; +struct B2 { + void foo(); +}; +struct Single : B1 { + void foo(); +}; +struct Multiple : B1, B2 { + void foo(); +}; +struct Virtual : virtual B1 { + int v; + void foo(); +}; struct POD { int a; int b; }; +struct Polymorphic { + virtual void myVirtual(); + int a; + int b; +}; + +// This class uses the virtual inheritance model, yet its vbptr offset is not 0. +// We still use zero for the null field offset, despite it being a valid field +// offset. +struct NonZeroVBPtr : POD, Virtual { + int n; +}; + +struct Unspecified; + +// Check that we can lower the LLVM types and get the null initializers right. +int Single ::*s_d_memptr; +int Polymorphic::*p_d_memptr; +int Multiple ::*m_d_memptr; +int Virtual ::*v_d_memptr; +int NonZeroVBPtr::*n_d_memptr; +int Unspecified::*u_d_memptr; +// CHECK: @"\01?s_d_memptr@@3PQSingle@@HA" = global i32 -1, align 4 +// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HA" = global i32 0, align 4 +// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HA" = global i32 -1, align 4 +// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HA" = global { i32, i32 } +// CHECK: { i32 0, i32 -1 }, align 4 +// CHECK: @"\01?n_d_memptr@@3PQNonZeroVBPtr@@HA" = global { i32, i32 } +// CHECK: { i32 0, i32 -1 }, align 4 +// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HA" = global { i32, i32, i32 } +// CHECK: { i32 0, i32 0, i32 -1 }, align 4 + +void (Single ::*s_f_memptr)(); +void (Multiple::*m_f_memptr)(); +void (Virtual ::*v_f_memptr)(); +// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZA" = global i8* null, align 4 +// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4 +// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4 + +// We can define Unspecified after locking in the inheritance model. +struct Unspecified : Virtual { + void foo(); + int u; +}; + +struct UnspecWithVBPtr; +int UnspecWithVBPtr::*forceUnspecWithVBPtr; +struct UnspecWithVBPtr : B1, virtual B2 { + int u; + void foo(); +}; + +// Test emitting non-virtual member pointers in a non-constexpr setting. +void EmitNonVirtualMemberPointers() { + void (Single ::*s_f_memptr)() = &Single::foo; + void (Multiple ::*m_f_memptr)() = &Multiple::foo; + void (Virtual ::*v_f_memptr)() = &Virtual::foo; + void (Unspecified::*u_f_memptr)() = &Unspecified::foo; + void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo; +// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() #0 { +// CHECK: alloca i8*, align 4 +// CHECK: alloca { i8*, i32 }, align 4 +// CHECK: alloca { i8*, i32, i32 }, align 4 +// CHECK: alloca { i8*, i32, i32, i32 }, align 4 +// CHECK: store i8* bitcast (void (%{{.*}}*)* @"\01?foo@Single@@QAEXXZ" to i8*), i8** %{{.*}}, align 4 +// CHECK: store { i8*, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Multiple@@QAEXXZ" to i8*), i32 0 }, +// CHECK: { i8*, i32 }* %{{.*}}, align 4 +// CHECK: store { i8*, i32, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, +// CHECK: { i8*, i32, i32 }* %{{.*}}, align 4 +// CHECK: store { i8*, i32, i32, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, +// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: store { i8*, i32, i32, i32 } +// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@UnspecWithVBPtr@@QAEXXZ" to i8*), +// CHECK: i32 0, i32 4, i32 0 }, +// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: ret void +// CHECK: } +} + void podMemPtrs() { int POD::*memptr; memptr = &POD::a; @@ -24,12 +124,6 @@ void podMemPtrs() { // CHECK: } } -struct Polymorphic { - virtual void myVirtual(); - int a; - int b; -}; - void polymorphicMemPtrs() { int Polymorphic::*memptr; memptr = &Polymorphic::a; @@ -49,3 +143,221 @@ void polymorphicMemPtrs() { // CHECK: ret void // CHECK: } } + +bool nullTestDataUnspecified(int Unspecified::*mp) { + return mp; +// CHECK: define zeroext i1 @"\01?nullTestDataUnspecified@@YA_NPQUnspecified@@H@Z"{{.*}} { +// CHECK: %{{.*}} = load { i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: store { i32, i32, i32 } {{.*}} align 4 +// CHECK: %[[mp:.*]] = load { i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: %[[mp0:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 0 +// CHECK: %[[cmp0:.*]] = icmp ne i32 %[[mp0]], 0 +// CHECK: %[[mp1:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 1 +// CHECK: %[[cmp1:.*]] = icmp ne i32 %[[mp1]], 0 +// CHECK: %[[and0:.*]] = and i1 %[[cmp0]], %[[cmp1]] +// CHECK: %[[mp2:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 2 +// CHECK: %[[cmp2:.*]] = icmp ne i32 %[[mp2]], -1 +// CHECK: %[[and1:.*]] = and i1 %[[and0]], %[[cmp2]] +// CHECK: ret i1 %[[and1]] +// CHECK: } +} + +bool nullTestFunctionUnspecified(void (Unspecified::*mp)()) { + return mp; +// CHECK: define zeroext i1 @"\01?nullTestFunctionUnspecified@@YA_NP8Unspecified@@AEXXZ@Z"{{.*}} { +// CHECK: %{{.*}} = load { i8*, i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: store { i8*, i32, i32, i32 } {{.*}} align 4 +// CHECK: %[[mp:.*]] = load { i8*, i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: %[[mp0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[mp]], 0 +// CHECK: %[[cmp0:.*]] = icmp ne i8* %[[mp0]], null +// CHECK: ret i1 %[[cmp0]] +// CHECK: } +} + +int loadDataMemberPointerVirtual(Virtual *o, int Virtual::*memptr) { + return o->*memptr; +// Test that we can unpack this aggregate member pointer and load the member +// data pointer. +// CHECK: define i32 @"\01?loadDataMemberPointerVirtual@@YAHPAUVirtual@@PQ1@H@Z"{{.*}} { +// CHECK: %[[o:.*]] = load %{{.*}}** %{{.*}}, align 4 +// CHECK: %[[memptr:.*]] = load { i32, i32 }* %{{.*}}, align 4 +// CHECK: %[[memptr0:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 0 +// CHECK: %[[memptr1:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 1 +// CHECK: %[[v6:.*]] = bitcast %{{.*}}* %[[o]] to i8* +// CHECK: %[[vbptr:.*]] = getelementptr inbounds i8* %[[v6]], i32 0 +// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8** +// CHECK: %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]] +// CHECK: %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr1]] +// CHECK: %[[v8:.*]] = bitcast i8* %[[v7]] to i32* +// CHECK: %[[vbase_offs:.*]] = load i32* %[[v8]] +// CHECK: %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]] +// CHECK: %[[offset:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr0]] +// CHECK: %[[v11:.*]] = bitcast i8* %[[offset]] to i32* +// CHECK: %[[v12:.*]] = load i32* %[[v11]] +// CHECK: ret i32 %[[v12]] +// CHECK: } +} + +int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) { + return o->*memptr; +// Test that we can unpack this aggregate member pointer and load the member +// data pointer. +// CHECK: define i32 @"\01?loadDataMemberPointerUnspecified@@YAHPAUUnspecified@@PQ1@H@Z"{{.*}} { +// CHECK: %[[o:.*]] = load %{{.*}}** %{{.*}}, align 4 +// CHECK: %[[memptr:.*]] = load { i32, i32, i32 }* %{{.*}}, align 4 +// CHECK: %[[memptr0:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 0 +// CHECK: %[[memptr1:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 1 +// CHECK: %[[memptr2:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 2 +// CHECK: %[[base:.*]] = bitcast %{{.*}}* %[[o]] to i8* +// CHECK: %[[is_vbase:.*]] = icmp ne i32 %[[memptr2]], 0 +// CHECK: br i1 %[[is_vbase]], label %[[vadjust:.*]], label %[[skip:.*]] +// +// CHECK: [[vadjust]] +// CHECK: %[[vbptr:.*]] = getelementptr inbounds i8* %[[base]], i32 %[[memptr1]] +// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8** +// CHECK: %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]] +// CHECK: %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]] +// CHECK: %[[v8:.*]] = bitcast i8* %[[v7]] to i32* +// CHECK: %[[vbase_offs:.*]] = load i32* %[[v8]] +// CHECK: %[[base_adj:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]] +// +// CHECK: [[skip]] +// CHECK: %[[new_base:.*]] = phi i8* [ %[[base]], %{{.*}} ], [ %[[base_adj]], %[[vadjust]] ] +// CHECK: %[[offset:.*]] = getelementptr inbounds i8* %[[new_base]], i32 %[[memptr0]] +// CHECK: %[[v11:.*]] = bitcast i8* %[[offset]] to i32* +// CHECK: %[[v12:.*]] = load i32* %[[v11]] +// CHECK: ret i32 %[[v12]] +// CHECK: } +} + +void callMemberPointerSingle(Single *o, void (Single::*memptr)()) { + (o->*memptr)(); +// Just look for an indirect thiscall. +// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} #0 { +// CHECK: call x86_thiscallcc void %{{.*}}(%{{.*}} %{{.*}}) +// CHECK: ret void +// CHECK: } +} + +void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) { + (o->*memptr)(); +// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} #0 { +// CHECK: %[[memptr0:.*]] = extractvalue { i8*, i32 } %{{.*}}, 0 +// CHECK: %[[memptr1:.*]] = extractvalue { i8*, i32 } %{{.*}}, 1 +// CHECK: %[[this_adjusted:.*]] = getelementptr inbounds i8* %{{.*}}, i32 %[[memptr1]] +// CHECK: %[[this:.*]] = bitcast i8* %[[this_adjusted]] to {{.*}} +// CHECK: %[[fptr:.*]] = bitcast i8* %[[memptr0]] to {{.*}} +// CHECK: call x86_thiscallcc void %[[fptr]](%{{.*}} %[[this]]) +// CHECK: ret void +// CHECK: } +} + +void callMemberPointerVirtualBase(Virtual *o, void (Virtual::*memptr)()) { + (o->*memptr)(); +// This shares a lot with virtual data member pointers. +// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} #0 { +// CHECK: %[[memptr0:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 0 +// CHECK: %[[memptr1:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 1 +// CHECK: %[[memptr2:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 2 +// CHECK: %[[vbptr:.*]] = getelementptr inbounds i8* %{{.*}}, i32 0 +// CHECK: %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8** +// CHECK: %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]] +// CHECK: %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]] +// CHECK: %[[v8:.*]] = bitcast i8* %[[v7]] to i32* +// CHECK: %[[vbase_offs:.*]] = load i32* %[[v8]] +// CHECK: %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]] +// CHECK: %[[this_adjusted:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr1]] +// CHECK: %[[fptr:.*]] = bitcast i8* %[[memptr0]] to void ({{.*}}) +// CHECK: %[[this:.*]] = bitcast i8* %[[this_adjusted]] to {{.*}} +// CHECK: call x86_thiscallcc void %[[fptr]](%{{.*}} %[[this]]) +// CHECK: ret void +// CHECK: } +} + +bool compareSingleFunctionMemptr(void (Single::*l)(), void (Single::*r)()) { + return l == r; +// Should only be one comparison here. +// CHECK: define zeroext i1 @"\01?compareSingleFunctionMemptr@@YA_NP8Single@@AEXXZ0@Z"{{.*}} { +// CHECK-NOT: icmp +// CHECK: %[[r:.*]] = icmp eq +// CHECK-NOT: icmp +// CHECK: ret i1 %[[r]] +// CHECK: } +} + +bool compareNeqSingleFunctionMemptr(void (Single::*l)(), void (Single::*r)()) { + return l != r; +// Should only be one comparison here. +// CHECK: define zeroext i1 @"\01?compareNeqSingleFunctionMemptr@@YA_NP8Single@@AEXXZ0@Z"{{.*}} { +// CHECK-NOT: icmp +// CHECK: %[[r:.*]] = icmp ne +// CHECK-NOT: icmp +// CHECK: ret i1 %[[r]] +// CHECK: } +} + +bool unspecFuncMemptrEq(void (Unspecified::*l)(), void (Unspecified::*r)()) { + return l == r; +// CHECK: define zeroext i1 @"\01?unspecFuncMemptrEq@@YA_NP8Unspecified@@AEXXZ0@Z"{{.*}} { +// CHECK: %[[lhs0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[l:.*]], 0 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r:.*]], 0 +// CHECK: %[[cmp0:.*]] = icmp eq i8* %[[lhs0]], %{{.*}} +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 1 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 1 +// CHECK: %[[cmp1:.*]] = icmp eq i32 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 2 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 2 +// CHECK: %[[cmp2:.*]] = icmp eq i32 +// CHECK: %[[res12:.*]] = and i1 %[[cmp1]], %[[cmp2]] +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 3 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 3 +// CHECK: %[[cmp3:.*]] = icmp eq i32 +// CHECK: %[[res123:.*]] = and i1 %[[res12]], %[[cmp3]] +// CHECK: %[[iszero:.*]] = icmp eq i8* %[[lhs0]], null +// CHECK: %[[bits_or_null:.*]] = or i1 %[[res123]], %[[iszero]] +// CHECK: %{{.*}} = and i1 %[[bits_or_null]], %[[cmp0]] +// CHECK: ret i1 %{{.*}} +// CHECK: } +} + +bool unspecFuncMemptrNeq(void (Unspecified::*l)(), void (Unspecified::*r)()) { + return l != r; +// CHECK: define zeroext i1 @"\01?unspecFuncMemptrNeq@@YA_NP8Unspecified@@AEXXZ0@Z"{{.*}} { +// CHECK: %[[lhs0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[l:.*]], 0 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r:.*]], 0 +// CHECK: %[[cmp0:.*]] = icmp ne i8* %[[lhs0]], %{{.*}} +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 1 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 1 +// CHECK: %[[cmp1:.*]] = icmp ne i32 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 2 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 2 +// CHECK: %[[cmp2:.*]] = icmp ne i32 +// CHECK: %[[res12:.*]] = or i1 %[[cmp1]], %[[cmp2]] +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[l]], 3 +// CHECK: %{{.*}} = extractvalue { i8*, i32, i32, i32 } %[[r]], 3 +// CHECK: %[[cmp3:.*]] = icmp ne i32 +// CHECK: %[[res123:.*]] = or i1 %[[res12]], %[[cmp3]] +// CHECK: %[[iszero:.*]] = icmp ne i8* %[[lhs0]], null +// CHECK: %[[bits_or_null:.*]] = and i1 %[[res123]], %[[iszero]] +// CHECK: %{{.*}} = or i1 %[[bits_or_null]], %[[cmp0]] +// CHECK: ret i1 %{{.*}} +// CHECK: } +} + +bool unspecDataMemptrEq(int Unspecified::*l, int Unspecified::*r) { + return l == r; +// CHECK: define zeroext i1 @"\01?unspecDataMemptrEq@@YA_NPQUnspecified@@H0@Z"{{.*}} { +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 0 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 0 +// CHECK: icmp eq i32 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 1 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 1 +// CHECK: icmp eq i32 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 2 +// CHECK: extractvalue { i32, i32, i32 } %{{.*}}, 2 +// CHECK: icmp eq i32 +// CHECK: and i1 +// CHECK: and i1 +// CHECK: ret i1 +// CHECK: } +} diff --git a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp new file mode 100644 index 0000000000000..060c1728586c1 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -0,0 +1,169 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-linux | FileCheck -check-prefix LINUX %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -cxx-abi microsoft | FileCheck -check-prefix WIN32 %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-win32 -cxx-abi microsoft | FileCheck -check-prefix WIN64 %s + +struct Empty {}; + +struct EmptyWithCtor { + EmptyWithCtor() {} +}; + +struct Small { + int x; +}; + +// This is a C++11 trivial and standard-layout struct but not a C++03 POD. +struct SmallCpp11NotCpp03Pod : Empty { + int x; +}; + +struct SmallWithCtor { + SmallWithCtor() {} + int x; +}; + +struct SmallWithVftable { + int x; + virtual void foo(); +}; + +struct Medium { + int x, y; +}; + +struct MediumWithCopyCtor { + MediumWithCopyCtor(); + MediumWithCopyCtor(const struct MediumWithCopyCtor &); + int x, y; +}; + +struct Big { + int a, b, c, d, e, f; +}; + +// Returning structs that fit into a register. +Small small_return() { return Small(); } +// LINUX: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result) +// WIN32: define i32 @"\01?small_return@@YA?AUSmall@@XZ"() +// WIN64: define i32 @"\01?small_return@@YA?AUSmall@@XZ"() + +Medium medium_return() { return Medium(); } +// LINUX: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result) +// WIN32: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"() +// WIN64: define i64 @"\01?medium_return@@YA?AUMedium@@XZ"() + +// Returning structs that fit into a register but are not POD. +SmallCpp11NotCpp03Pod small_non_pod_return() { return SmallCpp11NotCpp03Pod(); } +// LINUX: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) +// WIN32: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) +// WIN64: define void @"\01?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) + +SmallWithCtor small_with_ctor_return() { return SmallWithCtor(); } +// LINUX: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result) +// WIN32: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) +// WIN64: define void @"\01?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) + +SmallWithVftable small_with_vftable_return() { return SmallWithVftable(); } +// LINUX: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result) +// WIN32: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) +// WIN64: define void @"\01?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) + +MediumWithCopyCtor medium_with_copy_ctor_return() { return MediumWithCopyCtor(); } +// LINUX: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result) +// WIN32: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) +// WIN64: define void @"\01?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) + +// Returning a large struct that doesn't fit into a register. +Big big_return() { return Big(); } +// LINUX: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result) +// WIN32: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) +// WIN64: define void @"\01?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) + + +void small_arg(Small s) {} +// LINUX: define void @_Z9small_arg5Small(%struct.Small* byval align 4 %s) +// WIN32: define void @"\01?small_arg@@YAXUSmall@@@Z"(%struct.Small* byval align 4 %s) +// WIN64: define void @"\01?small_arg@@YAXUSmall@@@Z"(i32 %s.coerce) + +void medium_arg(Medium s) {} +// LINUX: define void @_Z10medium_arg6Medium(%struct.Medium* byval align 4 %s) +// WIN32: define void @"\01?medium_arg@@YAXUMedium@@@Z"(%struct.Medium* byval align 4 %s) +// WIN64: define void @"\01?medium_arg@@YAXUMedium@@@Z"(i64 %s.coerce) + +void small_arg_with_ctor(SmallWithCtor s) {} +// LINUX: define void @_Z19small_arg_with_ctor13SmallWithCtor(%struct.SmallWithCtor* byval align 4 %s) +// WIN32: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(%struct.SmallWithCtor* byval align 4 %s) +// WIN64: define void @"\01?small_arg_with_ctor@@YAXUSmallWithCtor@@@Z"(i32 %s.coerce) + +void small_arg_with_vftable(SmallWithVftable s) {} +// LINUX: define void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s) +// WIN32: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval align 4 %s) +// WIN64: define void @"\01?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* byval %s) + +void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {} +// LINUX: define void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s) +// WIN32: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval align 4 %s) +// WIN64: define void @"\01?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* byval %s) + +void big_arg(Big s) {} +// LINUX: define void @_Z7big_arg3Big(%struct.Big* byval align 4 %s) +// WIN32: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* byval align 4 %s) +// WIN64: define void @"\01?big_arg@@YAXUBig@@@Z"(%struct.Big* %s) + +// FIXME: Add WIN64 tests. Currently, even the method manglings are wrong (sic!). +class Class { + public: + Small thiscall_method_small() { return Small(); } + // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) + // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this) + + SmallWithCtor thiscall_method_small_with_ctor() { return SmallWithCtor(); } + // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this) + // WIN32: define {{.*}} x86_thiscallcc void @"\01?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this) + + Small __cdecl cdecl_method_small() { return Small(); } + // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) + // FIXME: Interesting, cdecl returns structures differently for instance + // methods and global functions. This is not supported by Clang yet... + // FIXME: Replace WIN32-NOT with WIN32 when this is fixed. + // WIN32-NOT: define {{.*}} void @"\01?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%struct.Small* noalias sret %agg.result, %class.Class* %this) + + Big __cdecl cdecl_method_big() { return Big(); } + // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this) + // WIN32: define {{.*}} void @"\01?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result, %class.Class* %this) + + void thiscall_method_arg(Empty s) {} + // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Empty(%class.Class* %this) + // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUEmpty@@@Z"(%class.Class* %this, %struct.Empty* byval align 4 %s) + + void thiscall_method_arg(EmptyWithCtor s) {} + // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13EmptyWithCtor(%class.Class* %this) + // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUEmptyWithCtor@@@Z"(%class.Class* %this, %struct.EmptyWithCtor* byval align 4 %s) + + void thiscall_method_arg(Small s) {} + // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Small(%class.Class* %this, %struct.Small* byval align 4 %s) + // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUSmall@@@Z"(%class.Class* %this, %struct.Small* byval align 4 %s) + + void thiscall_method_arg(SmallWithCtor s) {} + // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE13SmallWithCtor(%class.Class* %this, %struct.SmallWithCtor* byval align 4 %s) + // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUSmallWithCtor@@@Z"(%class.Class* %this, %struct.SmallWithCtor* byval align 4 %s) + + void thiscall_method_arg(Big s) {} + // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE3Big(%class.Class* %this, %struct.Big* byval align 4 %s) + // WIN32: define {{.*}} void @"\01?thiscall_method_arg@Class@@QAEXUBig@@@Z"(%class.Class* %this, %struct.Big* byval align 4 %s) +}; + +void use_class() { + Class c; + c.thiscall_method_small(); + c.thiscall_method_small_with_ctor(); + + c.cdecl_method_small(); + c.cdecl_method_big(); + + c.thiscall_method_arg(Empty()); + c.thiscall_method_arg(EmptyWithCtor()); + c.thiscall_method_arg(Small()); + c.thiscall_method_arg(SmallWithCtor()); + c.thiscall_method_arg(Big()); +} diff --git a/test/CodeGenCXX/pr15753.cpp b/test/CodeGenCXX/pr15753.cpp new file mode 100644 index 0000000000000..fd2000be6e3a4 --- /dev/null +++ b/test/CodeGenCXX/pr15753.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +template <typename T> static int Foo(T t); +template <typename T> +int Foo(T t) { + return t; +} +template<> int Foo<int>(int i) { + return i; +} + +// CHECK-NOT: define diff --git a/test/CodeGenCXX/scoped-enums-debug-info.cpp b/test/CodeGenCXX/scoped-enums-debug-info.cpp new file mode 100644 index 0000000000000..d3ef9f7068407 --- /dev/null +++ b/test/CodeGenCXX/scoped-enums-debug-info.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -g -o - %s | FileCheck %s +// Test that we are emitting debug info and base types for scoped enums. + +// CHECK: [ DW_TAG_enumeration_type ] [Color] {{.*}} [from int] +enum class Color { gray }; + +void f(Color); +void g() { + f(Color::gray); +} + +// CHECK: [ DW_TAG_enumeration_type ] [Colour] {{.*}} [from int] +enum struct Colour { grey }; + +void h(Colour); +void i() { + h(Colour::grey); +} + +// CHECK: [ DW_TAG_enumeration_type ] [Couleur] {{.*}} [from unsigned char] +enum class Couleur : unsigned char { gris }; + +void j(Couleur); +void k() { + j(Couleur::gris); +} diff --git a/test/CodeGenCXX/scoped-enums.cpp b/test/CodeGenCXX/scoped-enums.cpp index fca05098923c2..c20faaaf2e96d 100644 --- a/test/CodeGenCXX/scoped-enums.cpp +++ b/test/CodeGenCXX/scoped-enums.cpp @@ -7,3 +7,11 @@ void f(Color); void g() { f(Color::red); } + +// See that struct is handled equally. +enum struct Colour { grey }; + +void h(Colour); +void i() { + h(Colour::grey); +} diff --git a/test/CodeGenCXX/throw-expressions.cpp b/test/CodeGenCXX/throw-expressions.cpp index f04185b23f1b9..ba8a86881a63d 100644 --- a/test/CodeGenCXX/throw-expressions.cpp +++ b/test/CodeGenCXX/throw-expressions.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm-only -verify %s -Wno-unreachable-code -// expected-no-diagnostics +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -Wno-unreachable-code -Werror -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s int val = 42; int& test1() { @@ -19,3 +18,28 @@ void test3() { int test4() { return 1 ? throw val : val; } + +// PR15923 +int test5(bool x, bool y, int z) { + return (x ? throw 1 : y) ? z : throw 2; +} +// CHECK: define i32 @_Z5test5bbi( +// CHECK: br i1 +// +// x.true: +// CHECK: call void @__cxa_throw( +// CHECK-NEXT: unreachable +// +// x.false: +// CHECK: br i1 +// +// y.true: +// CHECK: load i32* +// CHECK: br label +// +// y.false: +// CHECK: call void @__cxa_throw( +// CHECK-NEXT: unreachable +// +// end: +// CHECK: ret i32 diff --git a/test/CodeGenCXX/tls-init-funcs.cpp b/test/CodeGenCXX/tls-init-funcs.cpp new file mode 100644 index 0000000000000..17299dcb7b6ce --- /dev/null +++ b/test/CodeGenCXX/tls-init-funcs.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8 -std=c++11 -S -emit-llvm %s -o - | FileCheck %s + +// CHECK: @a = internal thread_local global +// CHECK: @_tlv_atexit({{.*}}@_ZN1AD1Ev + +struct A { + ~A(); +}; + +thread_local A a; diff --git a/test/CodeGenCXX/vtable-debug-info.cpp b/test/CodeGenCXX/vtable-debug-info.cpp index 9294d20e7292f..8710c76e0bfa0 100644 --- a/test/CodeGenCXX/vtable-debug-info.cpp +++ b/test/CodeGenCXX/vtable-debug-info.cpp @@ -1,4 +1,4 @@ -// RUN: %clang -c -g %s -o /dev/null +// RUN: %clang -emit-llvm -S -g %s -o /dev/null // Radar 8730409 // XFAIL: win32 |