Skip to content
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
bool ObjCPropertyAccess,
bool AvoidPartialAvailabilityChecks,
ObjCInterfaceDecl *ClassReceiver) {
if (getLangOpts().SYCLIsDevice) {
if (auto VD = dyn_cast<VarDecl>(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<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
Expand Down
19 changes: 3 additions & 16 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,29 +321,16 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
return true;
}

bool VisitMemberExpr(MemberExpr *E) {
if (VarDecl *VD = dyn_cast<VarDecl>(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<VarDecl>(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<ParmVarDecl>(VD)) {
if (!IsConst && VD->hasGlobalStorage() && !VD->isStaticLocal() &&
!VD->isStaticDataMember() && !isa<ParmVarDecl>(VD)) {
if (VD->getTLSKind() != VarDecl::TLS_None)
SemaRef.Diag(E->getLocation(), diag::err_thread_unsupported);
SemaRef.Diag(E->getLocation(), diag::err_sycl_restrict)
Expand Down
22 changes: 22 additions & 0 deletions clang/test/SemaSYCL/sycl-device-static-restrict.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: %clang_cc1 -verify -fsyntax-only -fsycl-is-device %s
const int glob1 = 1;
int glob2 = 2;
template <typename name, typename Func>
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
// expected-note-re@+1{{called by 'kernel_single_task<fake_kernel, (lambda at {{.*}})>}}
kernelFunc();
}

int main() {
static int n = 0;
const static int l = 0;
kernel_single_task<class fake_kernel>([]() {
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;
}
130 changes: 67 additions & 63 deletions clang/test/SemaSYCL/sycl-restrict.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(){};
Expand All @@ -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<B *>(a) != 0;
}

template<typename N, typename L>
template <typename N, typename L>
__attribute__((sycl_kernel)) void kernel1(L l) {
l();
}
}
} // namespace Check_RTTI_Restriction

typedef struct Base {
virtual void f() const {}
Expand All @@ -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 {
;
Expand All @@ -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 {
;
Expand All @@ -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<class kernel_name>([]() {
Expand All @@ -146,58 +144,64 @@ 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 <typename name, typename Func>
__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<class fake_kernel>([]() { usage( &addInt ); });
kernel_single_task<class fake_kernel>([]() { usage(&addInt); });
return 0;
}

4 changes: 2 additions & 2 deletions clang/test/SemaSYCL/tls_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down