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: env LLDB_USE_NATIVE_PDB_READER=1 %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 | |