| // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -fsyntax-only -fsycl-is-device -verify %s |
| // RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -fsyntax-only -fsycl-is-device -verify %s |
| |
| // These tests are intended to validate that a sycl_kernel_entry_point attribute |
| // appearing in the declaration of a function template does not affect overload |
| // resolution or cause spurious errors during overload resolution due to either |
| // a substitution failure in the attribute argument or a semantic check of the |
| // attribute during instantiation of a specialization unless that specialization |
| // is selected by overload resolution. |
| |
| // FIXME: C++23 [temp.expl.spec]p12 states: |
| // FIXME: ... Similarly, attributes appearing in the declaration of a template |
| // FIXME: have no effect on an explicit specialization of that template. |
| // FIXME: Clang currently instantiates and propagates attributes from a function |
| // FIXME: template to its explicit specializations resulting in the following |
| // FIXME: spurious error. |
| struct S1; // #S1-decl |
| // expected-error@+4 {{incomplete type 'S1' named in nested name specifier}} |
| // expected-note@+5 {{in instantiation of function template specialization 'ok1<S1>' requested here}} |
| // expected-note@#S1-decl {{forward declaration of 'S1'}} |
| template<typename T> |
| [[clang::sycl_kernel_entry_point(typename T::invalid)]] void ok1() {} |
| template<> |
| void ok1<S1>() {} |
| void test_ok1() { |
| // ok1<S1>() is not a call to a SYCL kernel entry point function. |
| ok1<S1>(); |
| } |
| |
| // FIXME: The sycl_kernel_entry_point attribute should not be instantiated |
| // FIXME: until after overload resolution has completed. |
| struct S2; // #S2-decl |
| // expected-error@+6 {{incomplete type 'S2' named in nested name specifier}} |
| // expected-note@+10 {{in instantiation of function template specialization 'ok2<S2>' requested here}} |
| // expected-note@#S2-decl {{forward declaration of 'S2'}} |
| template<typename T> |
| [[clang::sycl_kernel_entry_point(T)]] void ok2(int) {} |
| template<typename T> |
| [[clang::sycl_kernel_entry_point(typename T::invalid)]] void ok2(long) {} |
| void test_ok2() { |
| // ok2(int) is a better match and is therefore selected by overload |
| // resolution; the attempted instantiation of ok2(long) should not produce |
| // an error for the substitution failure into the attribute argument. |
| ok2<S2>(2); |
| } |
| |
| // FIXME: The sycl_kernel_entry_point attribute should not be instantiated |
| // FIXME: until after overload resolution has completed. |
| struct S3; |
| struct Select3 { |
| using bad_type = int; |
| using good_type = S3; |
| }; |
| // expected-error@+5 {{'typename Select3::bad_type' (aka 'int') is not a valid SYCL kernel name type; a non-union class type is required}} |
| // expected-note@+9 {{in instantiation of function template specialization 'ok3<Select3>' requested here}} |
| template<typename T> |
| [[clang::sycl_kernel_entry_point(typename T::good_type)]] void ok3(int) {} |
| template<typename T> |
| [[clang::sycl_kernel_entry_point(typename T::bad_type)]] void ok3(long) {} |
| void test_ok3() { |
| // ok3(int) is a better match and is therefore selected by overload |
| // resolution; the attempted instantiation of ok3(long) should not produce |
| // an error for the invalid kernel name provided as the attribute argument. |
| ok3<Select3>(2); |
| } |