| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,275 @@ | ||
| // Tests without serialization: | ||
| // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \ | ||
| // RUN: -ast-dump %s \ | ||
| // RUN: | FileCheck --match-full-lines %s | ||
| // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \ | ||
| // RUN: -ast-dump %s \ | ||
| // RUN: | FileCheck --match-full-lines %s | ||
| // | ||
| // Tests with serialization: | ||
| // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \ | ||
| // RUN: -emit-pch -o %t %s | ||
| // RUN: %clang_cc1 -x c++ -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \ | ||
| // RUN: -include-pch %t -ast-dump-all /dev/null \ | ||
| // RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \ | ||
| // RUN: | FileCheck --match-full-lines %s | ||
| // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \ | ||
| // RUN: -emit-pch -o %t %s | ||
| // RUN: %clang_cc1 -x c++ -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \ | ||
| // RUN: -include-pch %t -ast-dump-all /dev/null \ | ||
| // RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \ | ||
| // RUN: | FileCheck --match-full-lines %s | ||
|
|
||
| // These tests validate the AST body produced for functions declared with the | ||
| // sycl_kernel_entry_point attribute. | ||
|
|
||
| // CHECK: TranslationUnitDecl {{.*}} | ||
|
|
||
| // A unique kernel name type is required for each declared kernel entry point. | ||
| template<int> struct KN; | ||
|
|
||
| // A unique invocable type for use with each declared kernel entry point. | ||
| template<int> struct K { | ||
| template<typename... Ts> | ||
| void operator()(Ts...) const {} | ||
| }; | ||
|
|
||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<1>)]] | ||
| void skep1() { | ||
| } | ||
| // CHECK: |-FunctionDecl {{.*}} skep1 'void ()' | ||
| // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}} | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}} | ||
| // CHECK-NEXT: | | `-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<1> | ||
|
|
||
| template<typename KNT, typename KT> | ||
| [[clang::sycl_kernel_entry_point(KNT)]] | ||
| void skep2(KT k) { | ||
| k(); | ||
| } | ||
| template | ||
| void skep2<KN<2>>(K<2>); | ||
| // CHECK: |-FunctionTemplateDecl {{.*}} skep2 | ||
| // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KNT | ||
| // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KT | ||
| // CHECK-NEXT: | |-FunctionDecl {{.*}} skep2 'void (KT)' | ||
| // CHECK-NEXT: | | |-ParmVarDecl {{.*}} k 'KT' | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-CallExpr {{.*}} '<dependent type>' | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT' | ||
| // CHECK-NEXT: | | `-SYCLKernelEntryPointAttr {{.*}} KNT | ||
|
|
||
| // CHECK-NEXT: | `-FunctionDecl {{.*}} skep2 'void (K<2>)' explicit_instantiation_definition | ||
| // CHECK-NEXT: | |-TemplateArgument type 'KN<2>' | ||
| // CHECK-NEXT: | | `-RecordType {{.*}} 'KN<2>' | ||
| // CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'KN' | ||
| // CHECK-NEXT: | |-TemplateArgument type 'K<2>' | ||
| // CHECK-NEXT: | | `-RecordType {{.*}} 'K<2>' | ||
| // CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'K' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'K<2>' | ||
| // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}} | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<2>' lvalue ParmVar {{.*}} 'k' 'K<2>' | ||
| // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}} | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<2>' | ||
| // CHECK-NEXT: | | `-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp> | ||
| // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'K<2>' lvalue ImplicitParam {{.*}} 'k' 'K<2>' | ||
| // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<2> | ||
|
|
||
| template<typename KNT, typename KT> | ||
| [[clang::sycl_kernel_entry_point(KNT)]] | ||
| void skep3(KT k) { | ||
| k(); | ||
| } | ||
| template<> | ||
| [[clang::sycl_kernel_entry_point(KN<3>)]] | ||
| void skep3<KN<3>>(K<3> k) { | ||
| k(); | ||
| } | ||
| // CHECK: |-FunctionTemplateDecl {{.*}} skep3 | ||
| // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KNT | ||
| // CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KT | ||
| // CHECK-NEXT: | |-FunctionDecl {{.*}} skep3 'void (KT)' | ||
| // CHECK-NEXT: | | |-ParmVarDecl {{.*}} k 'KT' | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-CallExpr {{.*}} '<dependent type>' | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT' | ||
| // CHECK-NEXT: | | `-SYCLKernelEntryPointAttr {{.*}} KNT | ||
|
|
||
| // CHECK-NEXT: | `-Function {{.*}} 'skep3' 'void (K<3>)' | ||
| // CHECK-NEXT: |-FunctionDecl {{.*}} skep3 'void (K<3>)' explicit_specialization | ||
| // CHECK-NEXT: | |-TemplateArgument type 'KN<3>' | ||
| // CHECK-NEXT: | | `-RecordType {{.*}} 'KN<3>' | ||
| // CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'KN' | ||
| // CHECK-NEXT: | |-TemplateArgument type 'K<3>' | ||
| // CHECK-NEXT: | | `-RecordType {{.*}} 'K<3>' | ||
| // CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'K' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'K<3>' | ||
| // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}} | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<3>' lvalue ParmVar {{.*}} 'k' 'K<3>' | ||
| // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}} | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<3>' | ||
| // CHECK-NEXT: | | `-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp> | ||
| // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'K<3>' lvalue ImplicitParam {{.*}} 'k' 'K<3>' | ||
| // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<3> | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<4>)]] | ||
| void skep4(K<4> k, int p1, int p2) { | ||
| k(p1, p2); | ||
| } | ||
| // CHECK: |-FunctionDecl {{.*}} skep4 'void (K<4>, int, int)' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'K<4>' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} p1 'int' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} p2 'int' | ||
| // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}} | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int) const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const' | ||
| // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp> | ||
| // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'K<4>' lvalue ParmVar {{.*}} 'k' 'K<4>' | ||
| // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> | ||
| // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p1' 'int' | ||
| // CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p2' 'int' | ||
| // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}} | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<4>' | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used p1 'int' | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used p2 'int' | ||
| // CHECK-NEXT: | | `-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int) const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<4>' lvalue ImplicitParam {{.*}} 'k' 'K<4>' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'p1' 'int' | ||
| // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> | ||
| // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'p2' 'int' | ||
| // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<4> | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<5>)]] | ||
| void skep5(int unused1, K<5> k, int unused2, int p, int unused3) { | ||
| static int slv = 0; | ||
| int lv = 4; | ||
| k(slv, 1, p, 3, lv, 5, []{ return 6; }); | ||
| } | ||
| // CHECK: |-FunctionDecl {{.*}} skep5 'void (int, K<5>, int, int, int)' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} unused1 'int' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} used k 'K<5>' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} unused2 'int' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} used p 'int' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} unused3 'int' | ||
| // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}} | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK: | | `-OutlinedFunctionDecl {{.*}} | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit unused1 'int' | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<5>' | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit unused2 'int' | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used p 'int' | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit unused3 'int' | ||
| // CHECK-NEXT: | | `-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | |-DeclStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-VarDecl {{.*}} used slv 'int' static cinit | ||
| // CHECK-NEXT: | | | `-IntegerLiteral {{.*}} 'int' 0 | ||
| // CHECK-NEXT: | | |-DeclStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-VarDecl {{.*}} used lv 'int' cinit | ||
| // CHECK-NEXT: | | | `-IntegerLiteral {{.*}} 'int' 4 | ||
| // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int, int, int, int, int, (lambda {{.*}}) const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int, int, int, int, int, (lambda {{.*}})) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int, int, int, int, int, (lambda {{.*}})) const' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'const K<5>' lvalue <NoOp> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<5>' lvalue ImplicitParam {{.*}} 'k' 'K<5>' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'slv' 'int' | ||
| // CHECK-NEXT: | | |-IntegerLiteral {{.*}} 'int' 1 | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'p' 'int' | ||
| // CHECK-NEXT: | | |-IntegerLiteral {{.*}} 'int' 3 | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'lv' 'int' | ||
| // CHECK-NEXT: | | |-IntegerLiteral {{.*}} 'int' 5 | ||
| // CHECK-NEXT: | | `-LambdaExpr {{.*}} '(lambda {{.*}})' | ||
| // CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5> | ||
|
|
||
| struct S6 { | ||
| void operator()() const; | ||
| }; | ||
| [[clang::sycl_kernel_entry_point(KN<6>)]] | ||
| void skep6(const S6 &k) { | ||
| k(); | ||
| } | ||
| // CHECK: |-FunctionDecl {{.*}} skep6 'void (const S6 &)' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} used k 'const S6 &' | ||
| // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}} | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'const S6' lvalue ParmVar {{.*}} 'k' 'const S6 &' | ||
| // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}} | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'const S6 &' | ||
| // CHECK-NEXT: | | `-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'const S6' lvalue ImplicitParam {{.*}} 'k' 'const S6 &' | ||
| // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<6> | ||
|
|
||
| // Parameter types are not required to be complete at the point of a | ||
| // non-defining declaration. | ||
| struct S7; | ||
| [[clang::sycl_kernel_entry_point(KN<7>)]] | ||
| void skep7(S7 k); | ||
| struct S7 { | ||
| void operator()() const; | ||
| }; | ||
| [[clang::sycl_kernel_entry_point(KN<7>)]] | ||
| void skep7(S7 k) { | ||
| k(); | ||
| } | ||
| // CHECK: |-FunctionDecl {{.*}} skep7 'void (S7)' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'S7' | ||
| // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<7> | ||
| // CHECK: |-FunctionDecl {{.*}} prev {{.*}} skep7 'void (S7)' | ||
| // CHECK-NEXT: | |-ParmVarDecl {{.*}} used k 'S7' | ||
| // CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}} | ||
| // CHECK-NEXT: | | |-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'S7' lvalue ParmVar {{.*}} 'k' 'S7' | ||
| // CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}} | ||
| // CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'S7' | ||
| // CHECK-NEXT: | | `-CompoundStmt {{.*}} | ||
| // CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()' | ||
| // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay> | ||
| // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const' | ||
| // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp> | ||
| // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'S7' lvalue ImplicitParam {{.*}} 'k' 'S7' | ||
| // CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<7> | ||
|
|
||
|
|
||
| void the_end() {} | ||
| // CHECK: `-FunctionDecl {{.*}} the_end 'void ()' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,249 @@ | ||
| // 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 validate appertainment for the sycl_kernel_entry_point attribute. | ||
|
|
||
| #if __cplusplus >= 202002L | ||
| // Mock coroutine support. | ||
| namespace std { | ||
|
|
||
| template<typename Promise = void> | ||
| struct coroutine_handle { | ||
| template<typename T> | ||
| coroutine_handle(const coroutine_handle<T>&); | ||
| static coroutine_handle from_address(void *addr); | ||
| }; | ||
|
|
||
| template<typename R, typename... Args> | ||
| struct coroutine_traits { | ||
| struct suspend_never { | ||
| bool await_ready() const noexcept; | ||
| void await_suspend(std::coroutine_handle<>) const noexcept; | ||
| void await_resume() const noexcept; | ||
| }; | ||
| struct promise_type { | ||
| void get_return_object() noexcept; | ||
| suspend_never initial_suspend() const noexcept; | ||
| suspend_never final_suspend() const noexcept; | ||
| void return_void() noexcept; | ||
| void unhandled_exception() noexcept; | ||
| }; | ||
| }; | ||
|
|
||
| } | ||
| #endif | ||
|
|
||
| // A unique kernel name type is required for each declared kernel entry point. | ||
| template<int, int = 0> struct KN; | ||
|
|
||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Valid declarations. | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| // Function declaration with GNU attribute spelling | ||
| __attribute__((sycl_kernel_entry_point(KN<1>))) | ||
| void ok1(); | ||
|
|
||
| // Function declaration with Clang attribute spelling. | ||
| [[clang::sycl_kernel_entry_point(KN<2>)]] | ||
| void ok2(); | ||
|
|
||
| // Function definition. | ||
| [[clang::sycl_kernel_entry_point(KN<3>)]] | ||
| void ok3() {} | ||
|
|
||
| // Function template definition. | ||
| template<typename KNT, typename T> | ||
| [[clang::sycl_kernel_entry_point(KNT)]] | ||
| void ok4(T) {} | ||
|
|
||
| // Function template explicit specialization. | ||
| template<> | ||
| [[clang::sycl_kernel_entry_point(KN<4,1>)]] | ||
| void ok4<KN<4,1>>(int) {} | ||
|
|
||
| // Function template explicit instantiation. | ||
| template void ok4<KN<4,2>, long>(long); | ||
|
|
||
| namespace NS { | ||
| // Function declaration at namespace scope. | ||
| [[clang::sycl_kernel_entry_point(KN<5>)]] | ||
| void ok5(); | ||
| } | ||
|
|
||
| struct S6 { | ||
| // Static member function declaration. | ||
| [[clang::sycl_kernel_entry_point(KN<6>)]] | ||
| static void ok6(); | ||
| }; | ||
|
|
||
| // Dependent friend function. | ||
| template<typename KNT> | ||
| struct S7 { | ||
| [[clang::sycl_kernel_entry_point(KNT)]] | ||
| friend void ok7(S7) {} | ||
| }; | ||
| void test_ok7() { | ||
| ok7(S7<KN<7>>{}); | ||
| } | ||
|
|
||
| // The sycl_kernel_entry_point attribute must match across declarations and | ||
| // cannot be added for the first time after a definition. | ||
| [[clang::sycl_kernel_entry_point(KN<8>)]] | ||
| void ok8(); | ||
| [[clang::sycl_kernel_entry_point(KN<8>)]] | ||
| void ok8(); | ||
| [[clang::sycl_kernel_entry_point(KN<9>)]] | ||
| void ok9(); | ||
| void ok9() {} | ||
| void ok10(); | ||
| [[clang::sycl_kernel_entry_point(KN<10>)]] | ||
| void ok10() {} | ||
|
|
||
| using VOID = void; | ||
| [[clang::sycl_kernel_entry_point(KN<11>)]] | ||
| VOID ok11(); | ||
| [[clang::sycl_kernel_entry_point(KN<12>)]] | ||
| const void ok12(); | ||
|
|
||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| // Invalid declarations. | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| struct Smain; | ||
| // expected-error@+1 {{'main' cannot be declared with the 'sycl_kernel_entry_point' attribute}} | ||
| [[clang::sycl_kernel_entry_point(Smain)]] | ||
| int main(); | ||
|
|
||
| template<int> struct BADKN; | ||
|
|
||
| struct B1 { | ||
| // Non-static data member declaration. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<1>)]] | ||
| int bad1; | ||
| }; | ||
|
|
||
| struct B2 { | ||
| // Static data member declaration. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<2>)]] | ||
| static int bad2; | ||
| }; | ||
|
|
||
| struct B3 { | ||
| // Non-static member function declaration. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<3>)]] | ||
| void bad3(); | ||
| }; | ||
|
|
||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| namespace bad4 [[clang::sycl_kernel_entry_point(BADKN<4>)]] {} | ||
|
|
||
| #if __cplusplus >= 202002L | ||
| // expected-error@+2 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| template<typename> | ||
| concept bad5 [[clang::sycl_kernel_entry_point(BADKN<5>)]] = true; | ||
| #endif | ||
|
|
||
| // Type alias declarations. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| typedef void bad6 [[clang::sycl_kernel_entry_point(BADKN<6>)]] (); | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| using bad7 [[clang::sycl_kernel_entry_point(BADKN<7>)]] = void(); | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| using bad8 [[clang::sycl_kernel_entry_point(BADKN<8>)]] = int; | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to types}} | ||
| using bad9 = int [[clang::sycl_kernel_entry_point(BADKN<9>)]]; | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to types}} | ||
| using bad10 = int() [[clang::sycl_kernel_entry_point(BADKN<10>)]]; | ||
|
|
||
| // Variable declaration. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<11>)]] | ||
| int bad11; | ||
|
|
||
| // Class declaration. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| struct [[clang::sycl_kernel_entry_point(BADKN<12>)]] bad12; | ||
|
|
||
| // Enumeration declaration. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| enum [[clang::sycl_kernel_entry_point(BADKN<13>)]] bad13 {}; | ||
|
|
||
| // Enumerator. | ||
| // expected-error@+2 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| enum { | ||
| bad14 [[clang::sycl_kernel_entry_point(BADKN<14>)]] | ||
| }; | ||
|
|
||
| // Attribute added after the definition. | ||
| // expected-error@+3 {{'sycl_kernel_entry_point' attribute cannot be added to a function after the function is defined}} | ||
| // expected-note@+1 {{previous definition is here}} | ||
| void bad15() {} | ||
| [[clang::sycl_kernel_entry_point(BADKN<15>)]] | ||
| void bad15(); | ||
|
|
||
| // The function must return void. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions with a 'void' return type}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<16>)]] | ||
| int bad16(); | ||
|
|
||
| // Function parameters. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| void bad17(void (fp [[clang::sycl_kernel_entry_point(BADKN<17>)]])()); | ||
|
|
||
| // Function template parameters. | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute only applies to functions}} | ||
| template<void (fp [[clang::sycl_kernel_entry_point(BADKN<18>)]])()> | ||
| void bad18(); | ||
|
|
||
| #if __cplusplus >= 202002L | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a coroutine function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<19>)]] | ||
| void bad19() { | ||
| co_return; | ||
| } | ||
| #endif | ||
|
|
||
| struct B20 { | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<20>)]] | ||
| B20(); | ||
| }; | ||
|
|
||
| struct B21 { | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a non-static member function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<21>)]] | ||
| ~B21(); | ||
| }; | ||
|
|
||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a variadic function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<22>)]] | ||
| void bad22(...); | ||
|
|
||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a deleted function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<23>)]] | ||
| void bad23() = delete; | ||
|
|
||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a constexpr function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<24>)]] | ||
| constexpr void bad24() {} | ||
|
|
||
| #if __cplusplus >= 202002L | ||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a consteval function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<25>)]] | ||
| consteval void bad25() {} | ||
| #endif | ||
|
|
||
| // expected-error@+1 {{'sycl_kernel_entry_point' attribute cannot be applied to a noreturn function}} | ||
| [[clang::sycl_kernel_entry_point(BADKN<26>)]] | ||
| [[noreturn]] void bad26(); | ||
|
|
||
| // expected-error@+3 {{attribute 'target' multiversioning cannot be combined with attribute 'sycl_kernel_entry_point'}} | ||
| __attribute__((target("avx"))) void bad27(); | ||
| [[clang::sycl_kernel_entry_point(BADKN<27>)]] | ||
| __attribute__((target("sse4.2"))) void bad27(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| // Test that SYCL kernel name conflicts that occur across module boundaries are | ||
| // properly diagnosed and that declarations are properly merged so that spurious | ||
| // conflicts are not reported. | ||
|
|
||
| // RUN: rm -rf %t | ||
| // RUN: split-file %s %t | ||
| // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ | ||
| // RUN: -std=c++17 -fsycl-is-host %t/test.cpp -verify | ||
| // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ | ||
| // RUN: -std=c++17 -fsycl-is-device %t/test.cpp -verify | ||
|
|
||
| #--- module.modulemap | ||
| module M1 { header "m1.h" } | ||
| module M2 { header "m2.h" } | ||
|
|
||
|
|
||
| #--- common.h | ||
| template<int> struct KN; | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<1>)]] | ||
| void common_test1() {} | ||
|
|
||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] | ||
| void common_test2() {} | ||
| template void common_test2<KN<2>>(); | ||
|
|
||
|
|
||
| #--- m1.h | ||
| #include "common.h" | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<3>)]] | ||
| void m1_test3() {} // << expected previous declaration note here. | ||
|
|
||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] | ||
| void m1_test4() {} // << expected previous declaration note here. | ||
| template void m1_test4<KN<4>>(); | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<5>)]] | ||
| void m1_test5() {} // << expected previous declaration note here. | ||
|
|
||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] | ||
| void m1_test6() {} // << expected previous declaration note here. | ||
| template void m1_test6<KN<6>>(); | ||
|
|
||
|
|
||
| #--- m2.h | ||
| #include "common.h" | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<3>)]] | ||
| void m2_test3() {} // << expected kernel name conflict here. | ||
|
|
||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] | ||
| void m2_test4() {} // << expected kernel name conflict here. | ||
| template void m2_test4<KN<4>>(); | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<7>)]] | ||
| void m2_test7() {} // << expected previous declaration note here. | ||
|
|
||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] | ||
| void m2_test8() {} // << expected previous declaration note here. | ||
| template void m2_test8<KN<8>>(); | ||
|
|
||
|
|
||
| #--- test.cpp | ||
| #include "m1.h" | ||
| #include "m2.h" | ||
|
|
||
| // Expected diagnostics for m1_test3() and m2_test3(): | ||
| // expected-error@m2.h:4 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@m1.h:12 {{previous declaration is here}} | ||
|
|
||
| // Expected diagnostics for m1_test4<KN<4>>() and m2_test4<KN<4>>(): | ||
| // expected-error@m2.h:8 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@m1.h:16 {{previous declaration is here}} | ||
|
|
||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@m1.h:4 {{previous declaration is here}} | ||
| [[clang::sycl_kernel_entry_point(KN<5>)]] | ||
| void test5() {} | ||
|
|
||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@m1.h:8 {{previous declaration is here}} | ||
| [[clang::sycl_kernel_entry_point(KN<6>)]] | ||
| void test6() {} | ||
|
|
||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@m2.h:12 {{previous declaration is here}} | ||
| [[clang::sycl_kernel_entry_point(KN<7>)]] | ||
| void test7() {} | ||
|
|
||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@m2.h:16 {{previous declaration is here}} | ||
| [[clang::sycl_kernel_entry_point(KN<8>)]] | ||
| void test8() {} | ||
|
|
||
| void f() { | ||
| common_test1(); | ||
| common_test2<KN<2>>(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // Test that SYCL kernel name conflicts that occur across PCH boundaries are | ||
| // properly diagnosed. | ||
|
|
||
| // RUN: rm -rf %t | ||
| // RUN: split-file %s %t | ||
| // RUN: %clang_cc1 -std=c++17 -fsycl-is-host -emit-pch -x c++-header \ | ||
| // RUN: %t/pch.h -o %t/pch.h.host.pch | ||
| // RUN: %clang_cc1 -std=c++17 -fsycl-is-host -verify \ | ||
| // RUN: -include-pch %t/pch.h.host.pch %t/test.cpp | ||
| // RUN: %clang_cc1 -std=c++17 -fsycl-is-device -emit-pch -x c++-header \ | ||
| // RUN: %t/pch.h -o %t/pch.h.device.pch | ||
| // RUN: %clang_cc1 -std=c++17 -fsycl-is-device -verify \ | ||
| // RUN: -include-pch %t/pch.h.device.pch %t/test.cpp | ||
|
|
||
| #--- pch.h | ||
| template<int> struct KN; | ||
|
|
||
| [[clang::sycl_kernel_entry_point(KN<1>)]] | ||
| void pch_test1() {} // << expected previous declaration note here. | ||
|
|
||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] | ||
| void pch_test2() {} // << expected previous declaration note here. | ||
| template void pch_test2<KN<2>>(); | ||
|
|
||
|
|
||
| #--- test.cpp | ||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@pch.h:4 {{previous declaration is here}} | ||
| [[clang::sycl_kernel_entry_point(KN<1>)]] | ||
| void test1() {} | ||
|
|
||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@pch.h:8 {{previous declaration is here}} | ||
| [[clang::sycl_kernel_entry_point(KN<2>)]] | ||
| void test2() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // 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 validate that the kernel name type argument provided to the | ||
| // sycl_kernel_entry_point attribute meets the requirements of a SYCL kernel | ||
| // name as described in section 5.2, "Naming of kernels", of the SYCL 2020 | ||
| // specification. | ||
|
|
||
| struct S1; | ||
| // expected-warning@+3 {{redundant 'sycl_kernel_entry_point' attribute}} | ||
| // expected-note@+1 {{previous attribute is here}} | ||
| [[clang::sycl_kernel_entry_point(S1), | ||
| clang::sycl_kernel_entry_point(S1)]] | ||
| void ok1(); | ||
|
|
||
| // expected-error@+1 {{'int' is not a valid SYCL kernel name type; a class type is required}} | ||
| [[clang::sycl_kernel_entry_point(int)]] void bad2(); | ||
|
|
||
| // expected-error@+1 {{'int ()' is not a valid SYCL kernel name type; a class type is required}} | ||
| [[clang::sycl_kernel_entry_point(int())]] void bad3(); | ||
|
|
||
| // expected-error@+1 {{'int (*)()' is not a valid SYCL kernel name type; a class type is required}} | ||
| [[clang::sycl_kernel_entry_point(int(*)())]] void bad4(); | ||
|
|
||
| // expected-error@+1 {{'int (&)()' is not a valid SYCL kernel name type; a class type is required}} | ||
| [[clang::sycl_kernel_entry_point(int(&)())]] void bad5(); | ||
|
|
||
| // expected-error@+1 {{'decltype(nullptr)' (aka 'std::nullptr_t') is not a valid SYCL kernel name type; a class type is required}} | ||
| [[clang::sycl_kernel_entry_point(decltype(nullptr))]] void bad6(); | ||
|
|
||
| union U7; // #U7-decl | ||
| // expected-error@+2 {{'U7' is not a valid SYCL kernel name type; a class type is required}} | ||
| // expected-note@#U7-decl {{'U7' declared here}} | ||
| [[clang::sycl_kernel_entry_point(U7)]] void bad7(); | ||
|
|
||
| enum E8 {}; // #E8-decl | ||
| // expected-error@+2 {{'E8' is not a valid SYCL kernel name type; a class type is required}} | ||
| // expected-note@#E8-decl {{'E8' declared here}} | ||
| [[clang::sycl_kernel_entry_point(E8)]] void bad8(); | ||
|
|
||
| enum E9 : int; // #E9-decl | ||
| // expected-error@+2 {{'E9' is not a valid SYCL kernel name type; a class type is required}} | ||
| // expected-note@#E9-decl {{'E9' declared here}} | ||
| [[clang::sycl_kernel_entry_point(E9)]] void bad9(); | ||
|
|
||
| struct B10 { | ||
| struct MS; | ||
| }; | ||
| // FIXME-expected-error@+1 {{'sycl_kernel_entry_point' attribute argument must be a forward declarable class type}} | ||
| [[clang::sycl_kernel_entry_point(B10::MS)]] void bad10(); | ||
|
|
||
| struct B11 { | ||
| struct MS; | ||
| }; | ||
| // FIXME-expected-error@+3 {{'sycl_kernel_entry_point' attribute argument must be a forward declarable class type}} | ||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(typename T::MS)]] void bad11() {} | ||
| template void bad11<B11>(); | ||
|
|
||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] void bad12(); | ||
| void f12() { | ||
| // FIXME-expected-error@+2 {{'sycl_kernel_entry_point' attribute argument must be a forward declarable class type}} | ||
| struct LS; | ||
| bad12<LS>(); | ||
| } | ||
|
|
||
| struct B13_1; | ||
| struct B13_2; | ||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument does not match prior declaration: 'B13_2' vs 'B13_1'}} | ||
| // expected-note@+1 {{'bad13' declared here}} | ||
| [[clang::sycl_kernel_entry_point(B13_1)]] void bad13(); | ||
| [[clang::sycl_kernel_entry_point(B13_2)]] void bad13() {} | ||
|
|
||
| struct B14_1; | ||
| struct B14_2; | ||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument does not match prior declaration: 'B14_2' vs 'B14_1'}} | ||
| // expected-note@+1 {{previous attribute is here}} | ||
| [[clang::sycl_kernel_entry_point(B14_1), | ||
| clang::sycl_kernel_entry_point(B14_2)]] | ||
| void bad14(); | ||
|
|
||
| struct B15; | ||
| // expected-error@+3 {{'sycl_kernel_entry_point' kernel name argument conflicts with a previous declaration}} | ||
| // expected-note@+1 {{previous declaration is here}} | ||
| [[clang::sycl_kernel_entry_point(B15)]] void bad15_1(); | ||
| [[clang::sycl_kernel_entry_point(B15)]] void bad15_2(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // 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 validate that substitution failures that occur in an argument of | ||
| // a sycl_kernel_entry_point attribute occur in the immediate context and | ||
| // therefore influence 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>() {} | ||
|
|
||
| // FIXME: A substitution failure that occurs during instantiation of an | ||
| // FIXME: attribute specifier sequence should make the declaration invalid for | ||
| // FIXME: overload resolution but should not elicit a diagnostic (assuming | ||
| // FIXME: another overload candidate is selected). | ||
| struct S2; // #S2-decl | ||
| // expected-error@+4 {{incomplete type 'S2' named in nested name specifier}} | ||
| // expected-note@+7 {{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(typename T::invalid)]] void ok2(int) {} | ||
| template<typename T> | ||
| [[clang::sycl_kernel_entry_point(T)]] void ok2(long) {} | ||
| void test_ok2() { | ||
| ok2<S2>(2); // ok2(int) would be a better match, but SFINAE should result | ||
| // in overload resolution selecting ok2(long). | ||
| } |