1 // RUN: %clang_cc1 %s -std=c++17 -triple x86_64-pc-windows-msvc -fsycl-is-device -verify -fsyntax-only -Wno-unused
2 // RUN: %clang_cc1 %s -std=c++17 -triple x86_64-linux-gnu -fsycl-is-device -verify -fsyntax-only -Wno-unused
3 
4 template <typename KernelName, typename KernelType>
5 [[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) { // #kernelSingleTask
6   kernelFunc();
7 }
8 
9 // kernel1 - expect error
10 // The current function is named with a lambda (i.e., takes a lambda as a
11 // template parameter. Call the builtin on the current function then it is
12 // passed to a kernel. Test that passing the given function to the unique
13 // stable name builtin and then to the kernel throws an error because the
14 // latter causes its name mangling to change.
15 template <typename Func>
16 void kernel1func(const Func &F1) {
17   constexpr const char *F1_output = __builtin_sycl_unique_stable_name(Func); // #USN_F1
18   // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
19   // expected-note@#kernel1func_call{{in instantiation of function template specialization}}
20   // expected-note@#USN_F1{{'__builtin_sycl_unique_stable_name' evaluated here}}
21   // expected-note@+1{{in instantiation of function template specialization}}
22   kernel_single_task<class kernel1>(F1); // #kernel1_call
23 }
24 
25 void callkernel1() {
26   kernel1func([]() {}); // #kernel1func_call
27 }
28 
29 // kernel2 - expect error
30 // The current function is named with a lambda (i.e., takes a lambda as a
31 // template parameter). Call the builtin on the given function,
32 // then an empty lambda is passed to kernel.
33 // Test that passing the given function to the unique stable name builtin and
34 // then passing a different lambda to the kernel still throws an error because
35 // the calling context is part of naming the kernel. Even though the given
36 // function (F2) is not passed to the kernel, its mangling changes due to
37 // kernel call with the unrelated lambda.
38 template <typename Func>
39 void kernel2func(const Func &F2) {
40   constexpr const char *F2_output = __builtin_sycl_unique_stable_name(Func); // #USN_F2
41   // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
42   // expected-note@#kernel2func_call{{in instantiation of function template specialization}}
43   // expected-note@#USN_F2{{'__builtin_sycl_unique_stable_name' evaluated here}}
44   // expected-note@+1{{in instantiation of function template specialization}}
45   kernel_single_task<class kernel2>([]() {});
46 }
47 
48 void callkernel2() {
49   kernel2func([]() {}); // #kernel2func_call
50 }
51 
52 template <template <typename> typename Outer, typename Inner>
53 struct S {
54   void operator()() const;
55 };
56 
57 template <typename Ty>
58 struct Tangerine {};
59 
60 template <typename Func>
61 void kernel3_4func(const Func &F) {
62   // Test that passing the same lambda to two kernels does not cause an error
63   // because the kernel uses do not interfere with each other or invalidate
64   // the stable name in any way.
65   kernel_single_task<class kernel3>(F);
66   kernel_single_task<class kernel4>(F);
67   // Using the same functor twice should be fine
68 }
69 
70 // kernel3 and kernel4 - expect no errors
71 void callkernel3_4() {
72   kernel3_4func([]() {});
73 }
74 
75 template <typename T>
76 static constexpr const char *output1 = __builtin_sycl_unique_stable_name(T);
77 
78 #define MACRO()                      \
79   auto l14 = []() { return 1; };     \
80   constexpr const char *l14_output = \
81       __builtin_sycl_unique_stable_name(decltype(l14));
82 
83 int main() {
84 
85   // kernel5 - expect no error
86   // Test that passing the lambda to the unique stable name builtin and then
87   // using the lambda in a way that does not  contribute to the kernel name
88   // does not cause an error because the  stable name is not invalidated in
89   // this situation.
90   auto l5 = []() {};
91   constexpr const char *l5_output =
92       __builtin_sycl_unique_stable_name(decltype(l5));
93   kernel_single_task<class kernel5>(
94       [=]() { l5(); }); // Used in the kernel, but not the kernel name itself
95 
96   // kernel6 - expect error
97   // Test that passing the lambda to the unique stable name builtin and then
98   // using the same lambda in the naming of a kernel causes a diagnostic on the
99   // kernel use due to the change in results to the stable name.
100   auto l6 = []() { return 1; };
101   constexpr const char *l6_output =
102       __builtin_sycl_unique_stable_name(decltype(l6)); // #USN_l6
103   // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
104   // expected-note@#USN_l6{{'__builtin_sycl_unique_stable_name' evaluated here}}
105   // expected-note@+1{{in instantiation of function template specialization}}
106   kernel_single_task<class kernel6>(l6); // Used in the kernel name after builtin
107 
108   // kernel7 - expect error
109   // Same as kernel11 (below) except make the lambda part of naming the kernel.
110   // Test that passing a lambda to the unique stable name builtin and then
111   // passing a second lambda to the kernel throws an error because the first
112   // lambda is included in the signature of the second lambda, hence it changes
113   // the mangling of the kernel.
114   auto l7 = []() { return 1; };
115   auto l8 = [](decltype(l7) *derp = nullptr) { return 2; };
116   constexpr const char *l7_output =
117       __builtin_sycl_unique_stable_name(decltype(l7)); // #USN_l7
118   // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
119   // expected-note@#USN_l7{{'__builtin_sycl_unique_stable_name' evaluated here}}
120   // expected-note@+1{{in instantiation of function template specialization}}
121   kernel_single_task<class kernel7>(l8);
122 
123   // kernel8 and kernel9 - expect error
124   // Tests that passing a lambda to the unique stable name builtin and passing it
125   // to a kernel called with an if constexpr branch causes a diagnostic on the
126   // kernel9 use due to the change in the results to the stable name. This happens
127   // even though the use of kernel9 happens in the false branch of a constexpr if
128   // because both the true and the false branches cause the instantiation of
129   // kernel_single_task.
130   auto l9 = []() { return 1; };
131   auto l10 = []() { return 2; };
132   constexpr const char *l10_output =
133       __builtin_sycl_unique_stable_name(decltype(l10)); // #USN_l10
134   if constexpr (1) {
135     kernel_single_task<class kernel8>(l9);
136   } else {
137     // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
138     // expected-note@#USN_l10{{'__builtin_sycl_unique_stable_name' evaluated here}}
139     // expected-note@+1{{in instantiation of function template specialization}}
140     kernel_single_task<class kernel9>(l10);
141   }
142 
143   // kernel11 - expect no error
144   // Test that passing a lambda to the unique stable name builtin and then
145   // passing a second lambda capturing the first one to the kernel does not
146   // throw an error because the first lambda is not involved in naming the
147   // kernel i.e., the mangling does not change.
148   auto l11 = []() { return 1; };
149   auto l12 = [l11]() { return 2; };
150   constexpr const char *l11_output =
151       __builtin_sycl_unique_stable_name(decltype(l11));
152   kernel_single_task<class kernel11>(l12);
153 
154   // kernel12 - expect an error
155   // Test that passing a lambda to the unique stable name builtin and then
156   // passing it to the kernel as a template template parameter causes a
157   // diagnostic on the kernel use due to template template parameter being
158   // involved in the mangling of the kernel name.
159   auto l13 = []() { return 1; };
160   constexpr const char *l13_output =
161       __builtin_sycl_unique_stable_name(decltype(l13)); // #USN_l13
162   // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
163   // expected-note@#USN_l13{{'__builtin_sycl_unique_stable_name' evaluated here}}
164   // expected-note@+1{{in instantiation of function template specialization}}
165   kernel_single_task<class kernel12>(S<Tangerine, decltype(l13)>{});
166 
167   // kernel13 - expect an error
168   // Test that passing a lambda to the unique stable name builtin within a macro
169   // and then calling the macro within the kernel causes an error on the kernel
170   // and diagnoses in all the expected places despite the use of a macro.
171   // expected-error@#kernelSingleTask{{kernel instantiation changes the result of an evaluated '__builtin_sycl_unique_stable_name'}}
172   // expected-note@#USN_MACRO{{'__builtin_sycl_unique_stable_name' evaluated here}}
173   // expected-note@+1{{in instantiation of function template specialization}}
174   kernel_single_task<class kernel13>(
175       []() {
176         MACRO(); // #USN_MACRO
177       });
178 }
179 
180 namespace NS {}
181 
182 void f() {
183   // expected-error@+1{{unknown type name 'bad_var'}}
184   __builtin_sycl_unique_stable_name(bad_var);
185   // expected-error@+1{{use of undeclared identifier 'bad'}}
186   __builtin_sycl_unique_stable_name(bad::type);
187   // expected-error@+1{{no type named 'still_bad' in namespace 'NS'}}
188   __builtin_sycl_unique_stable_name(NS::still_bad);
189 
190   // FIXME: warning about side-effects in an unevaluated context expected, but
191   // none currently emitted.
192   int i = 0;
193   __builtin_sycl_unique_stable_name(decltype(i++));
194 
195   // Tests that use within a VLA does not diagnose as a side-effecting use in
196   // an unevaluated context because the use within a VLA extent forces
197   // evaluation.
198   int j = 55;
199   __builtin_sycl_unique_stable_name(int[++j]); // no warning expected
200 }
201 
202 template <typename T>
203 void f2() {
204   // expected-error@+1{{no type named 'bad_val' in 'St'}}
205   __builtin_sycl_unique_stable_name(typename T::bad_val);
206   // expected-error@+1{{no type named 'bad_type' in 'St'}}
207   __builtin_sycl_unique_stable_name(typename T::bad_type);
208 }
209 
210 struct St {};
211 
212 void use() {
213   // expected-note@+1{{in instantiation of}}
214   f2<St>();
215 }
216