| 1 | // clang-format off |
| 2 | // REQUIRES: lld, x86 |
| 3 | |
| 4 | // RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -c /Fo%t.obj -- %s |
| 5 | // RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb |
| 6 | // RUN: %lldb -f %t.exe -s \ |
| 7 | // RUN: %p/Inputs/function-types-builtins.lldbinit | FileCheck %s |
| 8 | |
| 9 | // Test that we can display function signatures with simple builtin |
| 10 | // and pointer types. We do this by using `target variable` in lldb |
| 11 | // with global variables of type ptr-to-function or reference-to-function. |
| 12 | // This technique in general allows us to exercise most of LLDB's type |
| 13 | // system without a running process. |
| 14 | |
| 15 | // Define _fltused, since we're not linking against the MS C runtime, but use |
| 16 | // floats. |
| 17 | extern "C" int _fltused = 0; |
| 18 | |
| 19 | template<typename T> |
| 20 | struct MakeResult { |
| 21 | static T result() { |
| 22 | return T{}; |
| 23 | } |
| 24 | }; |
| 25 | |
| 26 | template<typename T> |
| 27 | struct MakeResult<T&> { |
| 28 | static T& result() { |
| 29 | static T t; |
| 30 | return t; |
| 31 | } |
| 32 | }; |
| 33 | |
| 34 | template<typename T> |
| 35 | struct MakeResult<T&&> { |
| 36 | static T&& result() { |
| 37 | static T t; |
| 38 | return static_cast<T&&>(t); |
| 39 | } |
| 40 | }; |
| 41 | |
| 42 | |
| 43 | void nullary() {} |
| 44 | |
| 45 | template<typename Arg> |
| 46 | void unary(Arg) { } |
| 47 | |
| 48 | template<typename Ret, int N> |
| 49 | Ret unaryret() { return MakeResult<Ret>::result(); } |
| 50 | |
| 51 | template<typename A1, typename A2> |
| 52 | void binary(A1, A2) { } |
| 53 | |
| 54 | int varargs(int, int, ...) { return 0; } |
| 55 | |
| 56 | // Make sure to test every builtin type at least once for completeness. We |
| 57 | // test these in the globals-fundamentals.cpp when they are the types of |
| 58 | // variables but it's possible to imagine a situation where things behave |
| 59 | // differently as function arguments or return values than they do with |
| 60 | // global variables. |
| 61 | |
| 62 | // some interesting cases with argument types. |
| 63 | auto aa = &unary<bool>; |
| 64 | // CHECK: (void (*)(bool)) aa = {{.*}} |
| 65 | auto ab = &unary<char>; |
| 66 | // CHECK: (void (*)(char)) ab = {{.*}} |
| 67 | auto ac = &unary<signed char>; |
| 68 | // CHECK: (void (*)(signed char)) ac = {{.*}} |
| 69 | auto ad = &unary<unsigned char>; |
| 70 | // CHECK: (void (*)(unsigned char)) ad = {{.*}} |
| 71 | auto ae = &unary<char16_t>; |
| 72 | // CHECK: (void (*)(char16_t)) ae = {{.*}} |
| 73 | auto af = &unary<char32_t>; |
| 74 | // CHECK: (void (*)(char32_t)) af = {{.*}} |
| 75 | auto ag = &unary<wchar_t>; |
| 76 | // CHECK: (void (*)(wchar_t)) ag = {{.*}} |
| 77 | auto ah = &unary<short>; |
| 78 | // CHECK: (void (*)(short)) ah = {{.*}} |
| 79 | auto ai = &unary<unsigned short>; |
| 80 | // CHECK: (void (*)(unsigned short)) ai = {{.*}} |
| 81 | auto aj = &unary<int>; |
| 82 | // CHECK: (void (*)(int)) aj = {{.*}} |
| 83 | auto ak = &unary<unsigned int>; |
| 84 | // CHECK: (void (*)(unsigned int)) ak = {{.*}} |
| 85 | auto al = &unary<long>; |
| 86 | // CHECK: (void (*)(long)) al = {{.*}} |
| 87 | auto am = &unary<unsigned long>; |
| 88 | // CHECK: (void (*)(unsigned long)) am = {{.*}} |
| 89 | auto an = &unary<long long>; |
| 90 | // CHECK: (void (*)(long long)) an = {{.*}} |
| 91 | auto ao = &unary<unsigned long long>; |
| 92 | // CHECK: (void (*)(unsigned long long)) ao = {{.*}} |
| 93 | auto aq = &unary<float>; |
| 94 | // CHECK: (void (*)(float)) aq = {{.*}} |
| 95 | auto ar = &unary<double>; |
| 96 | // CHECK: (void (*)(double)) ar = {{.*}} |
| 97 | |
| 98 | auto as = &unary<int*>; |
| 99 | // CHECK: (void (*)(int *)) as = {{.*}} |
| 100 | auto at = &unary<int**>; |
| 101 | // CHECK: (void (*)(int **)) at = {{.*}} |
| 102 | auto au = &unary<int&>; |
| 103 | // CHECK: (void (*)(int &)) au = {{.*}} |
| 104 | auto av = &unary<int&&>; |
| 105 | // CHECK: (void (*)(int &&)) av = {{.*}} |
| 106 | auto aw = &unary<const int*>; |
| 107 | // CHECK: (void (*)(const int *)) aw = {{.*}} |
| 108 | auto ax = &unary<volatile int*>; |
| 109 | // CHECK: (void (*)(volatile int *)) ax = {{.*}} |
| 110 | auto ay = &unary<const volatile int*>; |
| 111 | // CHECK: (void (*)(const volatile int *)) ay = {{.*}} |
| 112 | auto az = &unary<void*&>; |
| 113 | // CHECK: (void (*)(void *&)) az = {{.*}} |
| 114 | auto aaa = &unary<int(&)[5]>; |
| 115 | // CHECK: (void (*)(int (&)[5])) aaa = {{.*}} |
| 116 | auto aab = &unary<int(*)[5]>; |
| 117 | // CHECK: (void (*)(int (*)[5])) aab = {{.*}} |
| 118 | auto aac = &unary<int(&&)[5]>; |
| 119 | // CHECK: (void (*)(int (&&)[5])) aac = {{.*}} |
| 120 | auto aad = &unary<int(*const)[5]>; |
| 121 | // CHECK: (void (*)(int (*const)[5])) aad = {{.*}} |
| 122 | |
| 123 | |
| 124 | // same test cases with return values, note we can't overload on return type |
| 125 | // so we need to use a different instantiation each time. |
| 126 | auto ra = &unaryret<bool, 0>; |
| 127 | // CHECK: (bool (*)()) ra = {{.*}} |
| 128 | auto rb = &unaryret<char, 1>; |
| 129 | // CHECK: (char (*)()) rb = {{.*}} |
| 130 | auto rc = &unaryret<signed char, 2>; |
| 131 | // CHECK: (signed char (*)()) rc = {{.*}} |
| 132 | auto rd = &unaryret<unsigned char, 3>; |
| 133 | // CHECK: (unsigned char (*)()) rd = {{.*}} |
| 134 | auto re = &unaryret<char16_t, 4>; |
| 135 | // CHECK: (char16_t (*)()) re = {{.*}} |
| 136 | auto rf = &unaryret<char32_t, 5>; |
| 137 | // CHECK: (char32_t (*)()) rf = {{.*}} |
| 138 | auto rg = &unaryret<wchar_t, 6>; |
| 139 | // CHECK: (wchar_t (*)()) rg = {{.*}} |
| 140 | auto rh = &unaryret<short, 7>; |
| 141 | // CHECK: (short (*)()) rh = {{.*}} |
| 142 | auto ri = &unaryret<unsigned short, 8>; |
| 143 | // CHECK: (unsigned short (*)()) ri = {{.*}} |
| 144 | auto rj = &unaryret<int, 9>; |
| 145 | // CHECK: (int (*)()) rj = {{.*}} |
| 146 | auto rk = &unaryret<unsigned int, 10>; |
| 147 | // CHECK: (unsigned int (*)()) rk = {{.*}} |
| 148 | auto rl = &unaryret<long, 11>; |
| 149 | // CHECK: (long (*)()) rl = {{.*}} |
| 150 | auto rm = &unaryret<unsigned long, 12>; |
| 151 | // CHECK: (unsigned long (*)()) rm = {{.*}} |
| 152 | auto rn = &unaryret<long long, 13>; |
| 153 | // CHECK: (long long (*)()) rn = {{.*}} |
| 154 | auto ro = &unaryret<unsigned long long, 14>; |
| 155 | // CHECK: (unsigned long long (*)()) ro = {{.*}} |
| 156 | auto rq = &unaryret<float, 15>; |
| 157 | // CHECK: (float (*)()) rq = {{.*}} |
| 158 | auto rr = &unaryret<double, 16>; |
| 159 | // CHECK: (double (*)()) rr = {{.*}} |
| 160 | |
| 161 | auto rs = &unaryret<int*, 17>; |
| 162 | // CHECK: (int *(*)()) rs = {{.*}} |
| 163 | auto rt = &unaryret<int**, 18>; |
| 164 | // CHECK: (int **(*)()) rt = {{.*}} |
| 165 | auto ru = &unaryret<int&, 19>; |
| 166 | // CHECK: (int &(*)()) ru = {{.*}} |
| 167 | auto rv = &unaryret<int&&, 20>; |
| 168 | // CHECK: (int &&(*)()) rv = {{.*}} |
| 169 | auto rw = &unaryret<const int*, 21>; |
| 170 | // CHECK: (const int *(*)()) rw = {{.*}} |
| 171 | auto rx = &unaryret<volatile int*, 22>; |
| 172 | // CHECK: (volatile int *(*)()) rx = {{.*}} |
| 173 | auto ry = &unaryret<const volatile int*, 23>; |
| 174 | // CHECK: (const volatile int *(*)()) ry = {{.*}} |
| 175 | auto rz = &unaryret<void*&, 24>; |
| 176 | // CHECK: (void *&(*)()) rz = {{.*}} |
| 177 | |
| 178 | // FIXME: This output doesn't really look correct. It should probably be |
| 179 | // formatting this as `int(&)[5] (*)()`. |
| 180 | auto raa = &unaryret<int(&)[5], 25>; |
| 181 | // CHECK: (int (&(*)())[5]) raa = {{.*}} |
| 182 | auto rab = &unaryret<int(*)[5], 26>; |
| 183 | // CHECK: (int (*(*)())[5]) rab = {{.*}} |
| 184 | auto rac = &unaryret<int(&&)[5], 27>; |
| 185 | // CHECK: (int (&&(*)())[5]) rac = {{.*}} |
| 186 | auto rad = &unaryret<int(*const)[5], 28>; |
| 187 | // CHECK: (int (*const (*)())[5]) rad = {{.*}} |
| 188 | |
| 189 | |
| 190 | |
| 191 | // Function references, we only need a couple of these since most of the |
| 192 | // interesting cases are already tested. |
| 193 | auto &ref = unary<bool>; |
| 194 | // CHECK: (void (&)(bool)) ref = {{.*}} (&::ref = <no summary available>) |
| 195 | auto &ref2 = unary<volatile int*>; |
| 196 | // CHECK: (void (&)(volatile int *)) ref2 = {{.*}} (&::ref2 = <no summary available>) |
| 197 | auto &ref3 = varargs; |
| 198 | // CHECK: (int (&)(int, int, ...)) ref3 = {{.*}} (&::ref3 = <no summary available>) |
| 199 | |
| 200 | // Multiple arguments, as before, just something to make sure it works. |
| 201 | auto binp = &binary<int*, const int*>; |
| 202 | // CHECK: (void (*)(int *, const int *)) binp = {{.*}} |
| 203 | auto &binr = binary<int*, const int*>; |
| 204 | // CHECK: (void (&)(int *, const int *)) binr = {{.*}} (&::binr = <no summary available>) |
| 205 | |
| 206 | // And finally, a function with no arguments. |
| 207 | auto null = &nullary; |
| 208 | // CHECK: (void (*)()) null = {{.*}} |
| 209 | |
| 210 | // FIXME: These currently don't work because clang-cl emits incorrect debug info |
| 211 | // for std::nullptr_t. We should fix these in clang-cl. |
| 212 | auto rae = &unaryret<decltype(nullptr), 29>; |
| 213 | // CHECK: (std::nullptr_t (*)()) rae = {{.*}} |
| 214 | auto aae = &unary<decltype(nullptr)>; |
| 215 | // CHECK: (void (*)(std::nullptr_t)) aae = {{.*}} |
| 216 | |
| 217 | int main(int argc, char **argv) { |
| 218 | return 0; |
| 219 | } |
| 220 | |