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