| // RUN: %clang_cc1 %s -std=c++17 -triple x86_64-pc-windows-msvc -fsycl-is-device -verify -fsyntax-only -Wno-unused |
| // RUN: %clang_cc1 %s -std=c++17 -triple x86_64-linux-gnu -fsycl-is-device -verify -fsyntax-only -Wno-unused |
| |
| template <typename KernelName, typename KernelType> |
| [[clang::sycl_kernel]] void kernel_single_task(KernelType kernelFunc) { // #kernelSingleTask |
| kernelFunc(); |
| } |
| |
| // kernel1 - expect error |
| // The current function is named with a lambda (i.e., takes a lambda as a |
| // template parameter. Call the builtin on the current function then it is |
| // passed to a kernel. Test that passing the given function to the unique |
| // stable name builtin and then to the kernel throws an error because the |
| // latter causes its name mangling to change. |
| template <typename Func> |
| void kernel1func(const Func &F1) { |
| constexpr const char *F1_output = __builtin_sycl_unique_stable_name(Func); // #USN_F1 |
| kernel_single_task<class kernel1>(F1); // #kernel1_call |
| } |
| |
| void callkernel1() { |
| kernel1func([]() {}); // #kernel1func_call |
| } |
| |
| // kernel2 - expect error |
| // The current function is named with a lambda (i.e., takes a lambda as a |
| // template parameter). Call the builtin on the given function, |
| // then an empty lambda is passed to kernel. |
| // Test that passing the given function to the unique stable name builtin and |
| // then passing a different lambda to the kernel still throws an error because |
| // the calling context is part of naming the kernel. Even though the given |
| // function (F2) is not passed to the kernel, its mangling changes due to |
| // kernel call with the unrelated lambda. |
| template <typename Func> |
| void kernel2func(const Func &F2) { |
| constexpr const char *F2_output = __builtin_sycl_unique_stable_name(Func); // #USN_F2 |
| kernel_single_task<class kernel2>([]() {}); |
| } |
| |
| void callkernel2() { |
| kernel2func([]() {}); // #kernel2func_call |
| } |
| |
| template <template <typename> typename Outer, typename Inner> |
| struct S { |
| void operator()() const; |
| }; |
| |
| template <typename Ty> |
| struct Tangerine {}; |
| |
| template <typename Func> |
| void kernel3_4func(const Func &F) { |
| // Test that passing the same lambda to two kernels does not cause an error |
| // because the kernel uses do not interfere with each other or invalidate |
| // the stable name in any way. |
| kernel_single_task<class kernel3>(F); |
| kernel_single_task<class kernel4>(F); |
| // Using the same functor twice should be fine |
| } |
| |
| // kernel3 and kernel4 - expect no errors |
| void callkernel3_4() { |
| kernel3_4func([]() {}); |
| } |
| |
| template <typename T> |
| static constexpr const char *output1 = __builtin_sycl_unique_stable_name(T); |
| |
| #define MACRO() \ |
| auto l14 = []() { return 1; }; \ |
| constexpr const char *l14_output = \ |
| __builtin_sycl_unique_stable_name(decltype(l14)); |
| |
| int main() { |
| |
| // kernel5 - expect no error |
| // Test that passing the lambda to the unique stable name builtin and then |
| // using the lambda in a way that does not contribute to the kernel name |
| // does not cause an error because the stable name is not invalidated in |
| // this situation. |
| auto l5 = []() {}; |
| constexpr const char *l5_output = |
| __builtin_sycl_unique_stable_name(decltype(l5)); |
| kernel_single_task<class kernel5>( |
| [=]() { l5(); }); // Used in the kernel, but not the kernel name itself |
| |
| // kernel6 - expect no error |
| // Test that passing the lambda to the unique stable name builtin and then |
| // using the same lambda in the naming of a kernel does not cause a diagnostic |
| // on the kernel use due to the change in results to the stable name. |
| auto l6 = []() { return 1; }; |
| constexpr const char *l6_output = |
| __builtin_sycl_unique_stable_name(decltype(l6)); // #USN_l6 |
| kernel_single_task<class kernel6>(l6); // Used in the kernel name after builtin |
| |
| // kernel7 - expect no error |
| // Same as kernel11 (below) except make the lambda part of naming the kernel. |
| // Test that passing a lambda to the unique stable name builtin and then |
| // passing a second lambda to the kernel does not throw an error because the |
| // first lambda is included in the signature of the second lambda, but does |
| // not change the mangling of the kernel. |
| auto l7 = []() { return 1; }; |
| auto l8 = [](decltype(l7) *derp = nullptr) { return 2; }; |
| constexpr const char *l7_output = |
| __builtin_sycl_unique_stable_name(decltype(l7)); // #USN_l7 |
| kernel_single_task<class kernel7>(l8); |
| |
| // kernel8 and kernel9 - expect no error |
| // Tests that passing a lambda to the unique stable name builtin and passing |
| // it to a kernel called with an if constexpr branch does not cause a |
| // diagnostic on the kernel9 as it does not change the result to the stable |
| // name. This is interesting even though the use of kernel9 happens in the |
| // false branch of a constexpr if because both the true and the false branches |
| // cause the instantiation of kernel_single_task. |
| auto l9 = []() { return 1; }; |
| auto l10 = []() { return 2; }; |
| constexpr const char *l10_output = |
| __builtin_sycl_unique_stable_name(decltype(l10)); // #USN_l10 |
| if constexpr (1) { |
| kernel_single_task<class kernel8>(l9); |
| } else { |
| kernel_single_task<class kernel9>(l10); |
| } |
| |
| // kernel11 - expect no error |
| // Test that passing a lambda to the unique stable name builtin and then |
| // passing a second lambda capturing the first one to the kernel does not |
| // throw an error because the first lambda is not involved in naming the |
| // kernel i.e., the mangling does not change. |
| auto l11 = []() { return 1; }; |
| auto l12 = [l11]() { return 2; }; |
| constexpr const char *l11_output = |
| __builtin_sycl_unique_stable_name(decltype(l11)); |
| kernel_single_task<class kernel11>(l12); |
| |
| // kernel12 - expect no error |
| // Test that passing a lambda to the unique stable name builtin and then |
| // passing it to the kernel as a template template parameter does not cause a |
| // diagnostic on the kernel use due to template template parameter being |
| // involved in the mangling of the kernel name. |
| auto l13 = []() { return 1; }; |
| constexpr const char *l13_output = |
| __builtin_sycl_unique_stable_name(decltype(l13)); // #USN_l13 |
| kernel_single_task<class kernel12>(S<Tangerine, decltype(l13)>{}); |
| |
| // kernel13 - expect no error |
| // Test that passing a lambda to the unique stable name builtin within a macro |
| // and then calling the macro within the kernel does not cause an error on the |
| // kernel. |
| kernel_single_task<class kernel13>( |
| []() { |
| MACRO(); // #USN_MACRO |
| }); |
| } |
| |
| namespace NS {} |
| |
| void f() { |
| // expected-error@+1{{unknown type name 'bad_var'}} |
| __builtin_sycl_unique_stable_name(bad_var); |
| // expected-error@+1{{use of undeclared identifier 'bad'}} |
| __builtin_sycl_unique_stable_name(bad::type); |
| // expected-error@+1{{no type named 'still_bad' in namespace 'NS'}} |
| __builtin_sycl_unique_stable_name(NS::still_bad); |
| |
| // FIXME: warning about side-effects in an unevaluated context expected, but |
| // none currently emitted. |
| int i = 0; |
| __builtin_sycl_unique_stable_name(decltype(i++)); |
| |
| // Tests that use within a VLA does not diagnose as a side-effecting use in |
| // an unevaluated context because the use within a VLA extent forces |
| // evaluation. |
| int j = 55; |
| __builtin_sycl_unique_stable_name(int[++j]); // no warning expected |
| } |
| |
| template <typename T> |
| void f2() { |
| // expected-error@+1{{no type named 'bad_val' in 'St'}} |
| __builtin_sycl_unique_stable_name(typename T::bad_val); |
| // expected-error@+1{{no type named 'bad_type' in 'St'}} |
| __builtin_sycl_unique_stable_name(typename T::bad_type); |
| } |
| |
| struct St {}; |
| |
| void use() { |
| // expected-note@+1{{in instantiation of}} |
| f2<St>(); |
| } |
| |
| // A previous implementation resulted in this being an example of the |
| // kernel-ordering and lexical lambda ordering issue. |
| void out_of_order_use() { |
| auto x = [](){}; |
| auto y = [](){}; |
| |
| kernel_single_task<decltype(y)>(y); |
| constexpr auto USN =__builtin_sycl_unique_stable_name(decltype(y)); |
| (void)USN; |
| kernel_single_task<decltype(x)>(x); |
| } |