// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++17 -fsycl-is-host -verify %s // RUN: %clang_cc1 -triple spirv64-unknown-unknown -fsyntax-only -std=c++17 -fsycl-is-device -verify %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++20 -fsycl-is-host -verify %s // RUN: %clang_cc1 -triple spirv64-unknown-unknown -fsyntax-only -std=c++20 -fsycl-is-device -verify %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -std=c++23 -fsycl-is-host -verify %s // RUN: %clang_cc1 -triple spirv64-unknown-unknown -fsyntax-only -std=c++23 -fsycl-is-device -verify %s // These tests validate diagnostics for invalid use of 'this' in the body of // a function declared with the sycl_kernel_entry_point attribute. template struct remove_reference_t { using type = T; }; template struct remove_reference_t { using type = T; }; namespace std { struct type_info { virtual ~type_info(); }; } // namespace std // A generic kernel launch function. template void sycl_kernel_launch(const char *, Ts...) {} //////////////////////////////////////////////////////////////////////////////// // Valid declarations. //////////////////////////////////////////////////////////////////////////////// template struct KN; struct S1 { [[clang::sycl_kernel_entry_point(KN<1>)]] void ok1() { (void)sizeof(this); } }; struct S2 { [[clang::sycl_kernel_entry_point(KN<2>)]] void ok2() { (void)noexcept(this); } }; struct S3 { [[clang::sycl_kernel_entry_point(KN<3>)]] void ok3() { decltype(this) x = nullptr; } }; struct S4 { static void smf(); [[clang::sycl_kernel_entry_point(KN<4>)]] void ok4() { remove_reference_t::type::smf(); } }; struct S5 { int dm; void mf(); [[clang::sycl_kernel_entry_point(KN<5>)]] void ok5() { (void)typeid(*this); // S5 is not abstract, so 'this' is not evaluated. (void)typeid(dm); // 'int' is not an abstract class type; implicit 'this' is not evaluated. (void)typeid(mf()); // 'void' is not an abstract class type; implicit 'this' is not evaluated. } }; template struct S6 { void mf() noexcept(B); [[clang::sycl_kernel_entry_point(KN)]] void ok6() noexcept(noexcept(mf())) {} }; template void S6, false>::ok6(); template void S6, true>::ok6(); template struct S7 { void mf() noexcept(B); [[clang::sycl_kernel_entry_point(KN)]] void ok7() noexcept(noexcept(this->mf())) {} }; template void S7, false>::ok7(); template void S7, true>::ok7(); #if __cplusplus >= 202002L template struct S8 { void mf(T); [[clang::sycl_kernel_entry_point(KN)]] void ok8() requires(requires { mf(1); }) {} }; template void S8, int>::ok8(); template struct S9 { void mf(T); [[clang::sycl_kernel_entry_point(KN)]] void ok9() requires(requires { this->mf(1); }) {} }; template void S9, int>::ok9(); #endif //////////////////////////////////////////////////////////////////////////////// // Invalid declarations. //////////////////////////////////////////////////////////////////////////////// template struct BADKN; // expected-error@+3 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}} struct B1 { [[clang::sycl_kernel_entry_point(BADKN<1>)]] void bad1() { (void)this; } }; // expected-error@+4 {{'this' cannot be implicitly used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}} struct B2 { int dm; [[clang::sycl_kernel_entry_point(BADKN<2>)]] void bad2() { (void)dm; } }; // expected-error@+4 {{'this' cannot be implicitly used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}} struct B3 { void mf(); [[clang::sycl_kernel_entry_point(BADKN<3>)]] void bad3() { (void)mf(); } }; // expected-error@+4 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}} struct B4 { virtual void vmf() = 0; [[clang::sycl_kernel_entry_point(BADKN<4>)]] void bad4() { (void)typeid(*this); // B4 is abstract, so 'this' is evaluated. } }; // A diagnostic is not currently issued for uninstantiated definitions. In this // case, a declaration is instantiated, but a definition isn't. A diagnostic // will be issued if a definition is instantiated (as the next test exercises). struct B5 { template [[clang::sycl_kernel_entry_point(KN)]] void bad5() { (void)this; } }; extern template void B5::bad5>(); // expected-error@+4 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}} struct B6 { template [[clang::sycl_kernel_entry_point(KN)]] void bad6() { (void)this; } }; // expected-note@+1 {{in instantiation of function template specialization 'B6::bad6>' requested here}} template void B6::bad6>(); // A diagnostic is not currently issued for uninstantiated definitions. In this // case, a declaration is instantiated, but a definition isn't. A diagnostic // will be issued if a definition is instantiated (as the next test exercises). template struct B7 { [[clang::sycl_kernel_entry_point(KN)]] void bad7() { (void)this; } }; extern template void B7>::bad7(); // expected-error@+4 {{'this' cannot be used in a potentially evaluated expression in the body of a function declared with the 'clang::sycl_kernel_entry_point' attribute}} template struct B8 { [[clang::sycl_kernel_entry_point(KN)]] void bad8() { (void)this; } }; // expected-note@+1 {{in instantiation of member function 'B8>::bad8' requested here}} template void B8>::bad8(); #if __cplusplus >= 202302L struct B9 { // expected-error@+1 {{the 'clang::sycl_kernel_entry_point' attribute cannot be applied to a function with an explicit object parameter}} [[clang::sycl_kernel_entry_point(BADKN<9>)]] void bad9(this B9 self) { (void)self; } }; #endif