diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index dedcc212be901..8d8309146ddca 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10626,7 +10626,7 @@ def err_sycl_kernel_name_class_not_top_level : Error< "nest in a namespace: %0">; def err_sycl_restrict : Error< "SYCL kernel cannot " -"%select{use a global variable" +"%select{use a non-const global variable" "|use rtti" "|use a non-const static data variable" "|call a virtual function" diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 29f6d137af45f..bbebd926d9b24 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -210,6 +210,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, ObjCInterfaceDecl *ClassReceiver) { + if (getLangOpts().SYCLIsDevice) { + if (auto VD = dyn_cast(D)) { + if (VD->getStorageClass() == SC_Static && + !VD->getType().isConstant(Context)) + SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict) + << Sema::KernelNonConstStaticDataVariable; + } + } + SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa(D)) { // If there were any diagnostics suppressed by template argument deduction, diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index d47a934505cd0..d8bee50e3c82a 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -321,29 +321,16 @@ class MarkDeviceFunction : public RecursiveASTVisitor { return true; } - bool VisitMemberExpr(MemberExpr *E) { - if (VarDecl *VD = dyn_cast(E->getMemberDecl())) { - bool IsConst = VD->getType().getNonReferenceType().isConstQualified(); - if (!IsConst && VD->isStaticDataMember()) - SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) - << Sema::KernelNonConstStaticDataVariable; - } - return true; - } - bool VisitDeclRefExpr(DeclRefExpr *E) { - Decl* D = E->getDecl(); + Decl *D = E->getDecl(); if (SemaRef.isKnownGoodSYCLDecl(D)) return true; CheckSYCLType(E->getType(), E->getSourceRange()); if (VarDecl *VD = dyn_cast(D)) { bool IsConst = VD->getType().getNonReferenceType().isConstQualified(); - if (!IsConst && VD->isStaticDataMember()) - SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) - << Sema::KernelNonConstStaticDataVariable; - else if (!IsConst && VD->hasGlobalStorage() && !VD->isStaticLocal() && - !VD->isStaticDataMember() && !isa(VD)) { + if (!IsConst && VD->hasGlobalStorage() && !VD->isStaticLocal() && + !VD->isStaticDataMember() && !isa(VD)) { if (VD->getTLSKind() != VarDecl::TLS_None) SemaRef.Diag(E->getLocation(), diag::err_thread_unsupported); SemaRef.Diag(E->getLocation(), diag::err_sycl_restrict) diff --git a/clang/test/SemaSYCL/sycl-device-static-restrict.cpp b/clang/test/SemaSYCL/sycl-device-static-restrict.cpp new file mode 100644 index 0000000000000..fce763a4a978c --- /dev/null +++ b/clang/test/SemaSYCL/sycl-device-static-restrict.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -verify -fsyntax-only -fsycl-is-device %s +const int glob1 = 1; +int glob2 = 2; +template +__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { + // expected-note-re@+1{{called by 'kernel_single_task}} + kernelFunc(); +} + +int main() { + static int n = 0; + const static int l = 0; + kernel_single_task([]() { + int m = l; + m = glob1; + // expected-error@+1{{SYCL kernel cannot use a non-const static data variable}} + m = n; + // expected-error@+1{{SYCL kernel cannot use a non-const global variable}} + m = glob2; + }); + return 0; +} diff --git a/clang/test/SemaSYCL/sycl-restrict.cpp b/clang/test/SemaSYCL/sycl-restrict.cpp index 7ff51d16ff7e6..1a296f6db7d28 100644 --- a/clang/test/SemaSYCL/sycl-restrict.cpp +++ b/clang/test/SemaSYCL/sycl-restrict.cpp @@ -2,40 +2,39 @@ // RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -fno-sycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s // RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -DALLOW_FP=1 -fsycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s - namespace std { - class type_info; - typedef __typeof__(sizeof(int)) size_t; -} +class type_info; +typedef __typeof__(sizeof(int)) size_t; +} // namespace std namespace Check_User_Operators { -class Fraction -{ - // expected-error@+2 {{SYCL kernel cannot call a recursive function}} - // expected-note@+1 {{function implemented using recursion declared here}} - int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } - int n, d; +class Fraction { + // expected-error@+2 {{SYCL kernel cannot call a recursive function}} + // expected-note@+1 {{function implemented using recursion declared here}} + int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } + int n, d; + public: - Fraction(int n, int d = 1) : n(n/gcd(n, d)), d(d/gcd(n, d)) { } - int num() const { return n; } - int den() const { return d; } + Fraction(int n, int d = 1) : n(n / gcd(n, d)), d(d / gcd(n, d)) {} + int num() const { return n; } + int den() const { return d; } }; -bool operator==(const Fraction& lhs, const Fraction& rhs) -{ - new int; // expected-error {{SYCL kernel cannot allocate storage}} - return lhs.num() == rhs.num() && lhs.den() == rhs.den(); -}} +bool operator==(const Fraction &lhs, const Fraction &rhs) { + new int; // expected-error {{SYCL kernel cannot allocate storage}} + return lhs.num() == rhs.num() && lhs.den() == rhs.den(); +} +} // namespace Check_User_Operators namespace Check_VLA_Restriction { void no_restriction(int p) { - int index[p+2]; + int index[p + 2]; } void restriction(int p) { // expected-error@+1 {{variable length arrays are not supported for the current target}} - int index[p+2]; -} + int index[p + 2]; } +} // namespace Check_VLA_Restriction -void* operator new (std::size_t size, void* ptr) throw() { return ptr; }; +void *operator new(std::size_t size, void *ptr) throw() { return ptr; }; namespace Check_RTTI_Restriction { struct A { virtual ~A(){}; @@ -50,35 +49,38 @@ struct OverloadedNewDelete { void *operator new(std::size_t size) throw() { // expected-error@+1 {{SYCL kernel cannot allocate storage}} float *pt = new float; - return 0;} + return 0; + } // This overload does not allocate: no diagnostic. - void *operator new[](std::size_t size) throw() {return 0;} + void *operator new[](std::size_t size) throw() { return 0; } void operator delete(void *){}; void operator delete[](void *){}; }; bool isa_B(A *a) { Check_User_Operators::Fraction f1(3, 8), f2(1, 2), f3(10, 2); - if (f1 == f2) return false; + if (f1 == f2) + return false; Check_VLA_Restriction::restriction(7); // expected-error@+1 {{SYCL kernel cannot allocate storage}} int *ip = new int; - int i; int *p3 = new(&i) int; // no error on placement new + int i; + int *p3 = new (&i) int; // no error on placement new // expected-note@+1 {{called by 'isa_B'}} - OverloadedNewDelete *x = new( struct OverloadedNewDelete ); - auto y = new struct OverloadedNewDelete [5]; + OverloadedNewDelete *x = new (struct OverloadedNewDelete); + auto y = new struct OverloadedNewDelete[5]; // expected-error@+1 {{SYCL kernel cannot use rtti}} (void)typeid(int); // expected-error@+1 {{SYCL kernel cannot use rtti}} return dynamic_cast(a) != 0; } -template +template __attribute__((sycl_kernel)) void kernel1(L l) { l(); } -} +} // namespace Check_RTTI_Restriction typedef struct Base { virtual void f() const {} @@ -87,22 +89,19 @@ typedef struct Base { typedef struct A { static int stat_member; const static int const_stat_member; - constexpr static int constexpr_stat_member=0; + constexpr static int constexpr_stat_member = 0; - int fm(void) - { + int fm(void) { // expected-error@+1 {{SYCL kernel cannot use a non-const static data variable}} return stat_member; } } a_type; - b_type b; -using myFuncDef = int(int,int); +using myFuncDef = int(int, int); -void eh_ok(void) -{ +void eh_ok(void) { __float128 A; try { ; @@ -112,8 +111,7 @@ void eh_ok(void) throw 20; } -void eh_not_ok(void) -{ +void eh_not_ok(void) { // expected-error@+1 {{SYCL kernel cannot use exceptions}} try { ; @@ -134,7 +132,7 @@ void usage(myFuncDef functionPtr) { // expected-error@+2 {{SYCL kernel cannot call through a function pointer}} #endif if ((*functionPtr)(1, 2)) - // expected-error@+2 {{SYCL kernel cannot use a global variable}} + // expected-error@+2 {{SYCL kernel cannot use a non-const global variable}} // expected-error@+1 {{SYCL kernel cannot call a virtual function}} b.f(); Check_RTTI_Restriction::kernel1([]() { @@ -146,44 +144,51 @@ void usage(myFuncDef functionPtr) { } namespace ns { - int glob; +int glob; } extern "C++" { - int another_global = 5; - namespace AnotherNS { - int moar_globals = 5; - } +int another_global = 5; +namespace AnotherNS { +int moar_globals = 5; +} } int addInt(int n, int m) { - return n+m; + return n + m; } -int use2 ( a_type ab, a_type *abp ) { +int use2(a_type ab, a_type *abp) { - if (ab.constexpr_stat_member) return 2; - if (ab.const_stat_member) return 1; + if (ab.constexpr_stat_member) + return 2; + if (ab.const_stat_member) + return 1; // expected-error@+1 {{SYCL kernel cannot use a non-const static data variable}} - if (ab.stat_member) return 0; + if (ab.stat_member) + return 0; // expected-error@+1 {{SYCL kernel cannot use a non-const static data variable}} - if (abp->stat_member) return 0; - if (ab.fm()) return 0; - // expected-error@+1 {{SYCL kernel cannot use a global variable}} - return another_global ; - // expected-error@+1 {{SYCL kernel cannot use a global variable}} + if (abp->stat_member) + return 0; + // expected-note@+1 {{called by 'use2'}} + if (ab.fm()) + return 0; + // expected-error@+1 {{SYCL kernel cannot use a non-const global variable}} + return another_global; + // expected-error@+1 {{SYCL kernel cannot use a non-const global variable}} return ns::glob + - // expected-error@+1 {{SYCL kernel cannot use a global variable}} - AnotherNS::moar_globals; + // expected-error@+1 {{SYCL kernel cannot use a non-const global variable}} + AnotherNS::moar_globals; // expected-note@+1 {{called by 'use2'}} eh_not_ok(); - Check_RTTI_Restriction:: A *a; + Check_RTTI_Restriction::A *a; // expected-note@+1 2{{called by 'use2'}} - Check_RTTI_Restriction:: isa_B(a); + Check_RTTI_Restriction::isa_B(a); // expected-note@+1 {{called by 'use2'}} usage(&addInt); Check_User_Operators::Fraction f1(3, 8), f2(1, 2), f3(10, 2); // expected-note@+1 {{called by 'use2'}} - if (f1 == f2) return false; + if (f1 == f2) + return false; } template @@ -191,13 +196,12 @@ __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { kernelFunc(); a_type ab; a_type *p; - // expected-note@+1 5{{called by 'kernel_single_task}} + // expected-note@+1 7{{called by 'kernel_single_task}} use2(ab, p); } int main() { a_type ab; - kernel_single_task([]() { usage( &addInt ); }); + kernel_single_task([]() { usage(&addInt); }); return 0; } - diff --git a/clang/test/SemaSYCL/tls_error.cpp b/clang/test/SemaSYCL/tls_error.cpp index d029b8c3f83e0..5f8e14c6d1a76 100644 --- a/clang/test/SemaSYCL/tls_error.cpp +++ b/clang/test/SemaSYCL/tls_error.cpp @@ -5,10 +5,10 @@ extern __thread void (*__once_call)(); // expected-no-error void usage() { // expected-error@+2{{thread-local storage is not supported for the current target}} - // expected-error@+1{{SYCL kernel cannot use a global variable}} + // expected-error@+1{{SYCL kernel cannot use a non-const global variable}} __once_callable = 0; // expected-error@+3{{thread-local storage is not supported for the current target}} - // expected-error@+2{{SYCL kernel cannot use a global variable}} + // expected-error@+2{{SYCL kernel cannot use a non-const global variable}} // expected-error@+1{{SYCL kernel cannot call through a function pointer}} __once_call(); }