1 //===- SemaSYCL.cpp - Semantic Analysis for SYCL constructs ---------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // This implements Semantic Analysis for SYCL constructs. 9 //===----------------------------------------------------------------------===// 10 11 #include "clang/AST/Mangle.h" 12 #include "clang/Sema/Sema.h" 13 #include "clang/Sema/SemaDiagnostic.h" 14 15 using namespace clang; 16 17 // ----------------------------------------------------------------------------- 18 // SYCL device specific diagnostics implementation 19 // ----------------------------------------------------------------------------- 20 21 Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, 22 unsigned DiagID) { 23 assert(getLangOpts().SYCLIsDevice && 24 "Should only be called during SYCL compilation"); 25 FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext()); 26 SemaDiagnosticBuilder::Kind DiagKind = [this, FD] { 27 if (!FD) 28 return SemaDiagnosticBuilder::K_Nop; 29 if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) 30 return SemaDiagnosticBuilder::K_ImmediateWithCallStack; 31 return SemaDiagnosticBuilder::K_Deferred; 32 }(); 33 return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this); 34 } 35 36 static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { 37 if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) 38 return CAT->getSize() == 0; 39 return false; 40 } 41 42 void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, 43 llvm::DenseSet<QualType> Visited, 44 ValueDecl *DeclToCheck) { 45 assert(getLangOpts().SYCLIsDevice && 46 "Should only be called during SYCL compilation"); 47 // Emit notes only for the first discovered declaration of unsupported type 48 // to avoid mess of notes. This flag is to track that error already happened. 49 bool NeedToEmitNotes = true; 50 51 auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { 52 bool ErrorFound = false; 53 if (isZeroSizedArray(*this, TypeToCheck)) { 54 SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; 55 ErrorFound = true; 56 } 57 // Checks for other types can also be done here. 58 if (ErrorFound) { 59 if (NeedToEmitNotes) { 60 if (auto *FD = dyn_cast<FieldDecl>(D)) 61 SYCLDiagIfDeviceCode(FD->getLocation(), 62 diag::note_illegal_field_declared_here) 63 << FD->getType()->isPointerType() << FD->getType(); 64 else 65 SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at); 66 } 67 } 68 69 return ErrorFound; 70 }; 71 72 // In case we have a Record used do the DFS for a bad field. 73 SmallVector<const ValueDecl *, 4> StackForRecursion; 74 StackForRecursion.push_back(DeclToCheck); 75 76 // While doing DFS save how we get there to emit a nice set of notes. 77 SmallVector<const FieldDecl *, 4> History; 78 History.push_back(nullptr); 79 80 do { 81 const ValueDecl *Next = StackForRecursion.pop_back_val(); 82 if (!Next) { 83 assert(!History.empty()); 84 // Found a marker, we have gone up a level. 85 History.pop_back(); 86 continue; 87 } 88 QualType NextTy = Next->getType(); 89 90 if (!Visited.insert(NextTy).second) 91 continue; 92 93 auto EmitHistory = [&]() { 94 // The first element is always nullptr. 95 for (uint64_t Index = 1; Index < History.size(); ++Index) { 96 SYCLDiagIfDeviceCode(History[Index]->getLocation(), 97 diag::note_within_field_of_type) 98 << History[Index]->getType(); 99 } 100 }; 101 102 if (Check(NextTy, Next)) { 103 if (NeedToEmitNotes) 104 EmitHistory(); 105 NeedToEmitNotes = false; 106 } 107 108 // In case pointer/array/reference type is met get pointee type, then 109 // proceed with that type. 110 while (NextTy->isAnyPointerType() || NextTy->isArrayType() || 111 NextTy->isReferenceType()) { 112 if (NextTy->isArrayType()) 113 NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0}; 114 else 115 NextTy = NextTy->getPointeeType(); 116 if (Check(NextTy, Next)) { 117 if (NeedToEmitNotes) 118 EmitHistory(); 119 NeedToEmitNotes = false; 120 } 121 } 122 123 if (const auto *RecDecl = NextTy->getAsRecordDecl()) { 124 if (auto *NextFD = dyn_cast<FieldDecl>(Next)) 125 History.push_back(NextFD); 126 // When nullptr is discovered, this means we've gone back up a level, so 127 // the history should be cleaned. 128 StackForRecursion.push_back(nullptr); 129 llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion)); 130 } 131 } while (!StackForRecursion.empty()); 132 } 133