Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1191,6 +1191,13 @@ let Documentation = [SYCLKernelDocs]; } +def SYCLSpecialClass: InheritableAttr { + let Spellings = [Clang<"sycl_special_class">]; + let Subjects = SubjectList<[CXXRecord]>; + let LangOpts = [SYCL]; + let Documentation = [SYCLSpecialClassDocs]; +} + def C11NoReturn : InheritableAttr { let Spellings = [Keyword<"_Noreturn">]; let Subjects = SubjectList<[Function], ErrorDiag>; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -405,6 +405,65 @@ }]; } +def SYCLSpecialClassDocs : Documentation { + let Category = DocCatStmt; + let Content = [{ +The ``__attribute__((sycl_special_class))`` attribute is used in SYCL +headers to indicate that a class or a struct needs additional implementation when +it is passed from host to device. +Special classes/struct will have a mandatory __init method and an optional __finalize +method (__finalize method method is used only with stream type). __init method gives the +user additional information required. For instance, the kernel function arguments +list is derived from the arguments of the __init method. The arguments of the __init method +are copied into the kernel function argument list and __init and __finalize methods are called +at the beginning and the end of the kernel, respectively. +Please note that this is an attribute that is used for internal implementation and not intended +to be used by external users. + +The sntax of the attribute is as follows: + +.. code-block:: c++ + + class __attribute__((sycl_special_class)) accessor {}; + class [[clang::sycl_special_class]] accessor {}; + +This is a code example that illustrates the use of the attribute: + +.. code-block:: c++ + + class __attribute__((sycl_special_class)) SpecialType { + int F1; + int F2; + void __init(int f1) { + F1 = f1; + F2 = f1; + } + void __finalize() {} + public: + SpecialType() = default; + int getF2() const { return F2; } + }; + + int main () { + SpecialType T; + cgh.single_task([=]() { + T.getF2(); + }); +} + +This would trigger the following kernel entry point in the AST: + +.. code-block:: c++ + + void __sycl_kernel(int f1) { + SpecialType T; + T.__init(f1); + ... + T.__finalize() + } + }]; +} + def C11NoReturnDocs : Documentation { let Category = DocCatFunction; let Content = [{ Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -8054,6 +8054,9 @@ case ParsedAttr::AT_SYCLKernel: handleSYCLKernelAttr(S, D, AL); break; + case ParsedAttr::AT_SYCLSpecialClass: + handleSimpleAttribute(S, D, AL); + break; case ParsedAttr::AT_Format: handleFormatAttr(S, D, AL); break; Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -154,6 +154,7 @@ // CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function) // CHECK-NEXT: ReturnsTwice (SubjectMatchRule_function) +// CHECK-NEXT: SYCLSpecialClass (SubjectMatchRule_record) // CHECK-NEXT: ScopedLockable (SubjectMatchRule_record) // CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property) // CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member) Index: clang/test/SemaSYCL/special-class-attribute-on-non-sycl.cpp =================================================================== --- /dev/null +++ clang/test/SemaSYCL/special-class-attribute-on-non-sycl.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fsycl-is-device -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -x c++ %s + +#ifndef __SYCL_DEVICE_ONLY__ +// expected-warning@+5 {{'sycl_special_class' attribute ignored}} +#else +// expected-no-diagnostics +#endif + +class __attribute__((sycl_special_class)) special_class {}; + Index: clang/test/SemaSYCL/special-class-attribute.cpp =================================================================== --- /dev/null +++ clang/test/SemaSYCL/special-class-attribute.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fsycl-is-device -verify %s + +// No diagnostics +class [[clang::sycl_special_class]] class1 {}; +class __attribute__((sycl_special_class)) class2 {}; + +class class3; +class [[clang::sycl_special_class]] class3 {}; + +class class4; +class __attribute__((sycl_special_class)) class4 {}; + +class [[clang::sycl_special_class]] struct1 {}; +struct __attribute__((sycl_special_class)) struct2 {}; + +class [[clang::sycl_special_class]] class5 {}; +class special5 {}; + +class __attribute__((sycl_special_class)) class6; +class class6 {}; + + +// Only classes +[[clang::sycl_special_class]] int var1 = 0; // expected-warning {{'sycl_special_class' attribute only applies to classes}} +__attribute__((sycl_special_class)) int var2 = 0; // expected-warning {{'sycl_special_class' attribute only applies to classes}} + +[[clang::sycl_special_class]] void foo1(); // expected-warning {{'sycl_special_class' attribute only applies to classes}} +__attribute__((sycl_special_class)) void foo2(); // expected-warning {{'sycl_special_class' attribute only applies to classes}} + +// Attribute takes no arguments +class [[clang::sycl_special_class(1)]] class7 {}; // expected-error {{'sycl_special_class' attribute takes no arguments}} +class __attribute__((sycl_special_class(1))) class8 {}; // expected-error {{'sycl_special_class' attribute takes no arguments}} +