Fznamznon updated this revision to Diff 390376.
Fznamznon added a comment.
An attempt to fix review page
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D114080/new/
https://reviews.llvm.org/D114080
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaSYCL.cpp
clang/test/SemaSYCL/zero-length-arrays.cpp
Index: clang/test/SemaSYCL/zero-length-arrays.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaSYCL/zero-length-arrays.cpp
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -fsycl-is-device -triple spir64 -fsyntax-only -verify %s
+//
+// This test checks if compiler reports compilation error on an attempt to use
+// a zero-length array inside device code.
+
+template <typename Name, typename Func>
+__attribute__((sycl_kernel)) void kernel(const Func &kernelFunc) {
+ // expected-note@+1 5{{called by 'kernel}}
+ kernelFunc(); // #KernelObjCall
+}
+
+typedef float ZEROARR[0];
+
+struct Wrapper {
+ int A;
+ int BadArray[0]; // expected-note 3{{field of illegal type 'int[0]' declared here}}
+};
+
+struct WrapperOfWrapper { // expected-error 2{{zero-length arrays are not permitted in SYCL device code}}
+ Wrapper F; // expected-note 2{{within field of type 'Wrapper' declared here}}
+ ZEROARR *Ptr; //expected-note 5{{field of illegal pointer type 'ZEROARR *' (aka 'float (*)[0]') declared here}}
+};
+
+template <unsigned Size> struct InnerTemplated {
+ double Array[Size]; // expected-note 8{{field of illegal type 'double[0]' declared here}}
+};
+
+template <unsigned Size, typename Ty> struct Templated {
+ unsigned A;
+ Ty Arr[Size];
+ InnerTemplated<Size> Array[Size + 1]; // expected-note 8{{within field of type 'InnerTemplated<0U>[1]' declared here}}
+};
+
+struct KernelSt {
+ int A;
+ int BadArray[0]; // expected-note {{field of illegal type 'int[0]' declared here}}
+ void operator()() const {}
+};
+
+WrapperOfWrapper offendingFoo() {
+ // expected-note@+1 {{called by 'offendingFoo'}}
+ return WrapperOfWrapper{};
+}
+
+template <unsigned Size>
+void templatedContext() {
+ Templated<Size, float> Var;
+ // expected-error@#KernelObjCall 2{{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@#KernelObjCall {{called by 'kernel<TempContext, (lambda at}}
+ // expected-note@+1 {{in instantiation of function template specialization}}
+ kernel<class TempContext>([=] {
+ // expected-note@+1 {{within field of type 'Templated<0U, float>' declared here}}
+ (void)Var; // expected-error 2{{zero-length arrays are not permitted in SYCL device code}}
+ });
+ // expected-error@#KernelObjCall {{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+2 {{in instantiation of function template specialization}}
+ // expected-note@+1 {{within field of type 'Templated<0U, float>' declared here}}
+ kernel<class TempContext1>([Var] {
+ });
+}
+
+void foo(const unsigned X) {
+ int Arr[0]; // expected-note 2{{declared here}}
+ ZEROARR TypeDef; // expected-note {{declared here}}
+ ZEROARR *Ptr; // expected-note {{declared here}}
+ // expected-error@#KernelObjCall 3{{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+1 {{in instantiation of function template specialization}}
+ kernel<class Simple>([=]() {
+ (void)Arr; // expected-error {{zero-length arrays are not permitted in SYCL device code}}
+ (void)TypeDef; // expected-error {{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+1 {{field of illegal pointer type 'ZEROARR *' (aka 'float (*)[0]') declared here}}
+ (void)Ptr; // expected-error {{zero-length arrays are not permitted in SYCL device code}}
+ });
+ // expected-error@#KernelObjCall {{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+2 {{in instantiation of function template specialization}}
+ // expected-note@+1 {{field of illegal type 'int[0]' declared here}}
+ kernel<class Simple1>([Arr] { // expected-error {{zero-length arrays are not permitted in SYCL device code}}
+ });
+ WrapperOfWrapper St;
+ // expected-error@#KernelObjCall 2{{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+1 {{in instantiation of function template specialization}}
+ kernel<class SimpleStruct>([=] {
+ // expected-note@+1 {{within field of type 'WrapperOfWrapper' declared here}}
+ (void)St.F.BadArray; // expected-error 4{{zero-length arrays are not permitted in SYCL device code}}
+ });
+ // expected-error@#KernelObjCall 2{{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+2 {{in instantiation of function template specialization}}
+ // expected-note@+1 {{within field of type 'WrapperOfWrapper' declared here}}
+ kernel<class SimpleStruct1>([St] { // expected-error 2{{zero-length arrays are not permitted in SYCL device code}}
+ });
+
+ Templated<1, int> OK;
+ Templated<1 - 1, double> Weirdo;
+ Templated<0, float> Zero;
+ // expected-error@#KernelObjCall 4{{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+1 {{in instantiation of function template specialization}}
+ kernel<class UseTemplated>([=] {
+ (void)OK; // No errors expected
+ (void)Zero; // expected-error 2{{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+1 {{within field of type 'Templated<1 - 1, double>' declared here}}
+ int A = Weirdo.A; // expected-error 2{{zero-length arrays are not permitted in SYCL device code}}
+ });
+
+ // expected-note@#KernelObjCall {{called by 'kernel<UseTemplated1, (lambda at}}
+ // expected-error@#KernelObjCall 2{{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+2 {{in instantiation of function template specialization}}
+ // expected-note@+1 {{within field of type 'Templated<0, float>' declared here}}
+ kernel<class UseTemplated1>([Zero] { // expected-error 2{{zero-length arrays are not permitted in SYCL device code}}
+ });
+
+ templatedContext<10>();
+ // expected-note@+1 2{{in instantiation of function template specialization}}
+ templatedContext<0>();
+
+ KernelSt K;
+ // expected-error@#KernelObjCall {{zero-length arrays are not permitted in SYCL device code}}
+ // expected-note@+1 {{in instantiation of function template specialization}}
+ kernel<class UseFunctor>(K);
+
+ // expected-note@#KernelObjCall {{called by 'kernel<ReturnFromFunc, (lambda at}}
+ kernel<class ReturnFromFunc>([=] {
+ // expected-note@+1 {{called by 'operator()'}}
+ offendingFoo();
+ });
+}
Index: clang/lib/Sema/SemaSYCL.cpp
===================================================================
--- clang/lib/Sema/SemaSYCL.cpp
+++ clang/lib/Sema/SemaSYCL.cpp
@@ -48,3 +48,102 @@
return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack;
}
+
+static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
+ if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty))
+ return CAT->getSize() == 0;
+ return false;
+}
+
+void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
+ llvm::DenseSet<QualType> Visited,
+ ValueDecl *DeclToCheck) {
+ assert(getLangOpts().SYCLIsDevice &&
+ "Should only be called during SYCL compilation");
+ // Emit notes only for the first discovered declaration of unsupported type
+ // to avoid mess of notes. This flag is to track that error already happened.
+ bool NeedToEmitNotes = true;
+
+ auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
+ bool ErrorFound = false;
+ if (isZeroSizedArray(*this, TypeToCheck)) {
+ SYCLDiagIfDeviceCode(UsedAt, diag::err_sycl_zero_array_size);
+ ErrorFound = true;
+ }
+ // Checks for other types can also be done here.
+ if (ErrorFound) {
+ if (NeedToEmitNotes) {
+ if (auto *FD = dyn_cast<FieldDecl>(D)) {
+ SYCLDiagIfDeviceCode(FD->getLocation(),
+ diag::note_illegal_field_declared_here)
+ << FD->getType()->isPointerType() << FD->getType();
+ } else {
+ SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
+ }
+ }
+ }
+
+ return ErrorFound;
+ };
+
+ // In case we have a Record used do the DFS for a bad field.
+ SmallVector<const ValueDecl *, 4> StackForRecursion;
+ StackForRecursion.push_back(DeclToCheck);
+
+ // While doing DFS save how we get there to emit a nice set of notes.
+ SmallVector<const FieldDecl *, 4> History;
+ History.push_back(nullptr);
+
+ do {
+ const ValueDecl *Next = StackForRecursion.pop_back_val();
+ if (!Next) {
+ assert(!History.empty());
+ // Found a marker, we have gone up a level.
+ History.pop_back();
+ continue;
+ }
+ QualType NextTy = Next->getType();
+
+ if (!Visited.insert(NextTy).second)
+ continue;
+
+ auto EmitHistory = [&]() {
+ // The first element is always nullptr.
+ for (uint64_t Index = 1; Index < History.size(); ++Index) {
+ SYCLDiagIfDeviceCode(History[Index]->getLocation(),
+ diag::note_within_field_of_type)
+ << History[Index]->getType();
+ }
+ };
+
+ if (Check(NextTy, Next)) {
+ if (NeedToEmitNotes)
+ EmitHistory();
+ NeedToEmitNotes = false;
+ }
+
+ // In case pointer/array/reference type is met get pointee type, then
+ // proceed with that type.
+ while (NextTy->isAnyPointerType() || NextTy->isArrayType() ||
+ NextTy->isReferenceType()) {
+ if (NextTy->isArrayType())
+ NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0};
+ else
+ NextTy = NextTy->getPointeeType();
+ if (Check(NextTy, Next)) {
+ if (NeedToEmitNotes)
+ EmitHistory();
+ NeedToEmitNotes = false;
+ }
+ }
+
+ if (const auto *RecDecl = NextTy->getAsRecordDecl()) {
+ if (auto *NextFD = dyn_cast<FieldDecl>(Next))
+ History.push_back(NextFD);
+ // When nullptr is discovered, this means we've gone back up a level, so
+ // the history should be cleaned.
+ StackForRecursion.push_back(nullptr);
+ llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion));
+ }
+ } while (!StackForRecursion.empty());
+}
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -1858,6 +1858,15 @@
if (isUnevaluatedContext() || Ty.isNull())
return;
+ // The original idea behind checkTypeSupport function is that unused
+ // declarations can be replaced with an array of bytes of the same size during
+ // codegen, such replacement doesn't seem to be possible for types without
+ // constant byte size like zero length arrays. So, do a deep check for SYCL.
+ if (D && LangOpts.SYCLIsDevice) {
+ llvm::DenseSet<QualType> Visited;
+ deepTypeCheckForSYCLDevice(Loc, Visited, D);
+ }
+
Decl *C = cast<Decl>(getCurLexicalContext());
// Memcpy operations for structs containing a member with unsupported type
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -13114,6 +13114,9 @@
/// Adds Callee to DeviceCallGraph if we don't know if its caller will be
/// codegen'ed yet.
bool checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee);
+ void deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
+ llvm::DenseSet<QualType> Visited,
+ ValueDecl *DeclToCheck);
};
/// RAII object that enters a new expression evaluation context.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11392,6 +11392,8 @@
def warn_sycl_kernel_return_type : Warning<
"function template with 'sycl_kernel' attribute must have a 'void' return type">,
InGroup<IgnoredAttributes>;
+def err_sycl_zero_array_size : Error<
+ "zero-length arrays are not permitted in SYCL device code">;
def err_ext_int_bad_size : Error<"%select{signed|unsigned}0 _ExtInt must "
"have a bit size of at least %select{2|1}0">;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits