15ffd83dbSDimitry Andric //===- SemaSYCL.cpp - Semantic Analysis for SYCL constructs ---------------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric // This implements Semantic Analysis for SYCL constructs. 95ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 105ffd83dbSDimitry Andric 11fe6060f1SDimitry Andric #include "clang/AST/Mangle.h" 125ffd83dbSDimitry Andric #include "clang/Sema/Sema.h" 135ffd83dbSDimitry Andric #include "clang/Sema/SemaDiagnostic.h" 145ffd83dbSDimitry Andric 155ffd83dbSDimitry Andric using namespace clang; 165ffd83dbSDimitry Andric 175ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 185ffd83dbSDimitry Andric // SYCL device specific diagnostics implementation 195ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 205ffd83dbSDimitry Andric 21e8d8bef9SDimitry Andric Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, 225ffd83dbSDimitry Andric unsigned DiagID) { 235ffd83dbSDimitry Andric assert(getLangOpts().SYCLIsDevice && 245ffd83dbSDimitry Andric "Should only be called during SYCL compilation"); 255ffd83dbSDimitry Andric FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext()); 26e8d8bef9SDimitry Andric SemaDiagnosticBuilder::Kind DiagKind = [this, FD] { 275ffd83dbSDimitry Andric if (!FD) 28e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 295ffd83dbSDimitry Andric if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) 30e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_ImmediateWithCallStack; 31e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Deferred; 325ffd83dbSDimitry Andric }(); 33e8d8bef9SDimitry Andric return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this); 345ffd83dbSDimitry Andric } 355ffd83dbSDimitry Andric 365ffd83dbSDimitry Andric bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { 375ffd83dbSDimitry Andric assert(getLangOpts().SYCLIsDevice && 385ffd83dbSDimitry Andric "Should only be called during SYCL compilation"); 395ffd83dbSDimitry Andric assert(Callee && "Callee may not be null."); 405ffd83dbSDimitry Andric 41349cc55cSDimitry Andric // Errors in an unevaluated context don't need to be generated, 425ffd83dbSDimitry Andric // so we can safely skip them. 435ffd83dbSDimitry Andric if (isUnevaluatedContext() || isConstantEvaluated()) 445ffd83dbSDimitry Andric return true; 455ffd83dbSDimitry Andric 46e8d8bef9SDimitry Andric SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop; 475ffd83dbSDimitry Andric 48e8d8bef9SDimitry Andric return DiagKind != SemaDiagnosticBuilder::K_Immediate && 49e8d8bef9SDimitry Andric DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; 505ffd83dbSDimitry Andric } 51*04eeddc0SDimitry Andric 52*04eeddc0SDimitry Andric static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { 53*04eeddc0SDimitry Andric if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) 54*04eeddc0SDimitry Andric return CAT->getSize() == 0; 55*04eeddc0SDimitry Andric return false; 56*04eeddc0SDimitry Andric } 57*04eeddc0SDimitry Andric 58*04eeddc0SDimitry Andric void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, 59*04eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited, 60*04eeddc0SDimitry Andric ValueDecl *DeclToCheck) { 61*04eeddc0SDimitry Andric assert(getLangOpts().SYCLIsDevice && 62*04eeddc0SDimitry Andric "Should only be called during SYCL compilation"); 63*04eeddc0SDimitry Andric // Emit notes only for the first discovered declaration of unsupported type 64*04eeddc0SDimitry Andric // to avoid mess of notes. This flag is to track that error already happened. 65*04eeddc0SDimitry Andric bool NeedToEmitNotes = true; 66*04eeddc0SDimitry Andric 67*04eeddc0SDimitry Andric auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { 68*04eeddc0SDimitry Andric bool ErrorFound = false; 69*04eeddc0SDimitry Andric if (isZeroSizedArray(*this, TypeToCheck)) { 70*04eeddc0SDimitry Andric SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; 71*04eeddc0SDimitry Andric ErrorFound = true; 72*04eeddc0SDimitry Andric } 73*04eeddc0SDimitry Andric // Checks for other types can also be done here. 74*04eeddc0SDimitry Andric if (ErrorFound) { 75*04eeddc0SDimitry Andric if (NeedToEmitNotes) { 76*04eeddc0SDimitry Andric if (auto *FD = dyn_cast<FieldDecl>(D)) 77*04eeddc0SDimitry Andric SYCLDiagIfDeviceCode(FD->getLocation(), 78*04eeddc0SDimitry Andric diag::note_illegal_field_declared_here) 79*04eeddc0SDimitry Andric << FD->getType()->isPointerType() << FD->getType(); 80*04eeddc0SDimitry Andric else 81*04eeddc0SDimitry Andric SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at); 82*04eeddc0SDimitry Andric } 83*04eeddc0SDimitry Andric } 84*04eeddc0SDimitry Andric 85*04eeddc0SDimitry Andric return ErrorFound; 86*04eeddc0SDimitry Andric }; 87*04eeddc0SDimitry Andric 88*04eeddc0SDimitry Andric // In case we have a Record used do the DFS for a bad field. 89*04eeddc0SDimitry Andric SmallVector<const ValueDecl *, 4> StackForRecursion; 90*04eeddc0SDimitry Andric StackForRecursion.push_back(DeclToCheck); 91*04eeddc0SDimitry Andric 92*04eeddc0SDimitry Andric // While doing DFS save how we get there to emit a nice set of notes. 93*04eeddc0SDimitry Andric SmallVector<const FieldDecl *, 4> History; 94*04eeddc0SDimitry Andric History.push_back(nullptr); 95*04eeddc0SDimitry Andric 96*04eeddc0SDimitry Andric do { 97*04eeddc0SDimitry Andric const ValueDecl *Next = StackForRecursion.pop_back_val(); 98*04eeddc0SDimitry Andric if (!Next) { 99*04eeddc0SDimitry Andric assert(!History.empty()); 100*04eeddc0SDimitry Andric // Found a marker, we have gone up a level. 101*04eeddc0SDimitry Andric History.pop_back(); 102*04eeddc0SDimitry Andric continue; 103*04eeddc0SDimitry Andric } 104*04eeddc0SDimitry Andric QualType NextTy = Next->getType(); 105*04eeddc0SDimitry Andric 106*04eeddc0SDimitry Andric if (!Visited.insert(NextTy).second) 107*04eeddc0SDimitry Andric continue; 108*04eeddc0SDimitry Andric 109*04eeddc0SDimitry Andric auto EmitHistory = [&]() { 110*04eeddc0SDimitry Andric // The first element is always nullptr. 111*04eeddc0SDimitry Andric for (uint64_t Index = 1; Index < History.size(); ++Index) { 112*04eeddc0SDimitry Andric SYCLDiagIfDeviceCode(History[Index]->getLocation(), 113*04eeddc0SDimitry Andric diag::note_within_field_of_type) 114*04eeddc0SDimitry Andric << History[Index]->getType(); 115*04eeddc0SDimitry Andric } 116*04eeddc0SDimitry Andric }; 117*04eeddc0SDimitry Andric 118*04eeddc0SDimitry Andric if (Check(NextTy, Next)) { 119*04eeddc0SDimitry Andric if (NeedToEmitNotes) 120*04eeddc0SDimitry Andric EmitHistory(); 121*04eeddc0SDimitry Andric NeedToEmitNotes = false; 122*04eeddc0SDimitry Andric } 123*04eeddc0SDimitry Andric 124*04eeddc0SDimitry Andric // In case pointer/array/reference type is met get pointee type, then 125*04eeddc0SDimitry Andric // proceed with that type. 126*04eeddc0SDimitry Andric while (NextTy->isAnyPointerType() || NextTy->isArrayType() || 127*04eeddc0SDimitry Andric NextTy->isReferenceType()) { 128*04eeddc0SDimitry Andric if (NextTy->isArrayType()) 129*04eeddc0SDimitry Andric NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0}; 130*04eeddc0SDimitry Andric else 131*04eeddc0SDimitry Andric NextTy = NextTy->getPointeeType(); 132*04eeddc0SDimitry Andric if (Check(NextTy, Next)) { 133*04eeddc0SDimitry Andric if (NeedToEmitNotes) 134*04eeddc0SDimitry Andric EmitHistory(); 135*04eeddc0SDimitry Andric NeedToEmitNotes = false; 136*04eeddc0SDimitry Andric } 137*04eeddc0SDimitry Andric } 138*04eeddc0SDimitry Andric 139*04eeddc0SDimitry Andric if (const auto *RecDecl = NextTy->getAsRecordDecl()) { 140*04eeddc0SDimitry Andric if (auto *NextFD = dyn_cast<FieldDecl>(Next)) 141*04eeddc0SDimitry Andric History.push_back(NextFD); 142*04eeddc0SDimitry Andric // When nullptr is discovered, this means we've gone back up a level, so 143*04eeddc0SDimitry Andric // the history should be cleaned. 144*04eeddc0SDimitry Andric StackForRecursion.push_back(nullptr); 145*04eeddc0SDimitry Andric llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion)); 146*04eeddc0SDimitry Andric } 147*04eeddc0SDimitry Andric } while (!StackForRecursion.empty()); 148*04eeddc0SDimitry Andric } 149