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 bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { 37 assert(getLangOpts().SYCLIsDevice && 38 "Should only be called during SYCL compilation"); 39 assert(Callee && "Callee may not be null."); 40 41 // Errors in an unevaluated context don't need to be generated, 42 // so we can safely skip them. 43 if (isUnevaluatedContext() || isConstantEvaluated()) 44 return true; 45 46 SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop; 47 48 return DiagKind != SemaDiagnosticBuilder::K_Immediate && 49 DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; 50 } 51 52 static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { 53 if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) 54 return CAT->getSize() == 0; 55 return false; 56 } 57 58 void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, 59 llvm::DenseSet<QualType> Visited, 60 ValueDecl *DeclToCheck) { 61 assert(getLangOpts().SYCLIsDevice && 62 "Should only be called during SYCL compilation"); 63 // Emit notes only for the first discovered declaration of unsupported type 64 // to avoid mess of notes. This flag is to track that error already happened. 65 bool NeedToEmitNotes = true; 66 67 auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { 68 bool ErrorFound = false; 69 if (isZeroSizedArray(*this, TypeToCheck)) { 70 SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; 71 ErrorFound = true; 72 } 73 // Checks for other types can also be done here. 74 if (ErrorFound) { 75 if (NeedToEmitNotes) { 76 if (auto *FD = dyn_cast<FieldDecl>(D)) 77 SYCLDiagIfDeviceCode(FD->getLocation(), 78 diag::note_illegal_field_declared_here) 79 << FD->getType()->isPointerType() << FD->getType(); 80 else 81 SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at); 82 } 83 } 84 85 return ErrorFound; 86 }; 87 88 // In case we have a Record used do the DFS for a bad field. 89 SmallVector<const ValueDecl *, 4> StackForRecursion; 90 StackForRecursion.push_back(DeclToCheck); 91 92 // While doing DFS save how we get there to emit a nice set of notes. 93 SmallVector<const FieldDecl *, 4> History; 94 History.push_back(nullptr); 95 96 do { 97 const ValueDecl *Next = StackForRecursion.pop_back_val(); 98 if (!Next) { 99 assert(!History.empty()); 100 // Found a marker, we have gone up a level. 101 History.pop_back(); 102 continue; 103 } 104 QualType NextTy = Next->getType(); 105 106 if (!Visited.insert(NextTy).second) 107 continue; 108 109 auto EmitHistory = [&]() { 110 // The first element is always nullptr. 111 for (uint64_t Index = 1; Index < History.size(); ++Index) { 112 SYCLDiagIfDeviceCode(History[Index]->getLocation(), 113 diag::note_within_field_of_type) 114 << History[Index]->getType(); 115 } 116 }; 117 118 if (Check(NextTy, Next)) { 119 if (NeedToEmitNotes) 120 EmitHistory(); 121 NeedToEmitNotes = false; 122 } 123 124 // In case pointer/array/reference type is met get pointee type, then 125 // proceed with that type. 126 while (NextTy->isAnyPointerType() || NextTy->isArrayType() || 127 NextTy->isReferenceType()) { 128 if (NextTy->isArrayType()) 129 NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0}; 130 else 131 NextTy = NextTy->getPointeeType(); 132 if (Check(NextTy, Next)) { 133 if (NeedToEmitNotes) 134 EmitHistory(); 135 NeedToEmitNotes = false; 136 } 137 } 138 139 if (const auto *RecDecl = NextTy->getAsRecordDecl()) { 140 if (auto *NextFD = dyn_cast<FieldDecl>(Next)) 141 History.push_back(NextFD); 142 // When nullptr is discovered, this means we've gone back up a level, so 143 // the history should be cleaned. 144 StackForRecursion.push_back(nullptr); 145 llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion)); 146 } 147 } while (!StackForRecursion.empty()); 148 } 149