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 11*0fca6ea1SDimitry Andric #include "clang/Sema/SemaSYCL.h" 12fe6060f1SDimitry Andric #include "clang/AST/Mangle.h" 13*0fca6ea1SDimitry Andric #include "clang/Sema/Attr.h" 14*0fca6ea1SDimitry Andric #include "clang/Sema/ParsedAttr.h" 155ffd83dbSDimitry Andric #include "clang/Sema/Sema.h" 165ffd83dbSDimitry Andric #include "clang/Sema/SemaDiagnostic.h" 175ffd83dbSDimitry Andric 185ffd83dbSDimitry Andric using namespace clang; 195ffd83dbSDimitry Andric 205ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 215ffd83dbSDimitry Andric // SYCL device specific diagnostics implementation 225ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 235ffd83dbSDimitry Andric 24*0fca6ea1SDimitry Andric SemaSYCL::SemaSYCL(Sema &S) : SemaBase(S) {} 25*0fca6ea1SDimitry Andric 26*0fca6ea1SDimitry Andric Sema::SemaDiagnosticBuilder SemaSYCL::DiagIfDeviceCode(SourceLocation Loc, 275ffd83dbSDimitry Andric unsigned DiagID) { 285ffd83dbSDimitry Andric assert(getLangOpts().SYCLIsDevice && 295ffd83dbSDimitry Andric "Should only be called during SYCL compilation"); 30*0fca6ea1SDimitry Andric FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.getCurLexicalContext()); 31e8d8bef9SDimitry Andric SemaDiagnosticBuilder::Kind DiagKind = [this, FD] { 325ffd83dbSDimitry Andric if (!FD) 33e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 34*0fca6ea1SDimitry Andric if (SemaRef.getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) 35e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_ImmediateWithCallStack; 36e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Deferred; 375ffd83dbSDimitry Andric }(); 38*0fca6ea1SDimitry Andric return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, SemaRef); 395ffd83dbSDimitry Andric } 405ffd83dbSDimitry Andric 41*0fca6ea1SDimitry Andric static bool isZeroSizedArray(SemaSYCL &S, QualType Ty) { 42*0fca6ea1SDimitry Andric if (const auto *CAT = S.getASTContext().getAsConstantArrayType(Ty)) 43*0fca6ea1SDimitry Andric return CAT->isZeroSize(); 4404eeddc0SDimitry Andric return false; 4504eeddc0SDimitry Andric } 4604eeddc0SDimitry Andric 47*0fca6ea1SDimitry Andric void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt, 4804eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited, 4904eeddc0SDimitry Andric ValueDecl *DeclToCheck) { 5004eeddc0SDimitry Andric assert(getLangOpts().SYCLIsDevice && 5104eeddc0SDimitry Andric "Should only be called during SYCL compilation"); 5204eeddc0SDimitry Andric // Emit notes only for the first discovered declaration of unsupported type 5304eeddc0SDimitry Andric // to avoid mess of notes. This flag is to track that error already happened. 5404eeddc0SDimitry Andric bool NeedToEmitNotes = true; 5504eeddc0SDimitry Andric 5604eeddc0SDimitry Andric auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { 5704eeddc0SDimitry Andric bool ErrorFound = false; 5804eeddc0SDimitry Andric if (isZeroSizedArray(*this, TypeToCheck)) { 59*0fca6ea1SDimitry Andric DiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; 6004eeddc0SDimitry Andric ErrorFound = true; 6104eeddc0SDimitry Andric } 6204eeddc0SDimitry Andric // Checks for other types can also be done here. 6304eeddc0SDimitry Andric if (ErrorFound) { 6404eeddc0SDimitry Andric if (NeedToEmitNotes) { 6504eeddc0SDimitry Andric if (auto *FD = dyn_cast<FieldDecl>(D)) 66*0fca6ea1SDimitry Andric DiagIfDeviceCode(FD->getLocation(), 6704eeddc0SDimitry Andric diag::note_illegal_field_declared_here) 6804eeddc0SDimitry Andric << FD->getType()->isPointerType() << FD->getType(); 6904eeddc0SDimitry Andric else 70*0fca6ea1SDimitry Andric DiagIfDeviceCode(D->getLocation(), diag::note_declared_at); 7104eeddc0SDimitry Andric } 7204eeddc0SDimitry Andric } 7304eeddc0SDimitry Andric 7404eeddc0SDimitry Andric return ErrorFound; 7504eeddc0SDimitry Andric }; 7604eeddc0SDimitry Andric 7704eeddc0SDimitry Andric // In case we have a Record used do the DFS for a bad field. 7804eeddc0SDimitry Andric SmallVector<const ValueDecl *, 4> StackForRecursion; 7904eeddc0SDimitry Andric StackForRecursion.push_back(DeclToCheck); 8004eeddc0SDimitry Andric 8104eeddc0SDimitry Andric // While doing DFS save how we get there to emit a nice set of notes. 8204eeddc0SDimitry Andric SmallVector<const FieldDecl *, 4> History; 8304eeddc0SDimitry Andric History.push_back(nullptr); 8404eeddc0SDimitry Andric 8504eeddc0SDimitry Andric do { 8604eeddc0SDimitry Andric const ValueDecl *Next = StackForRecursion.pop_back_val(); 8704eeddc0SDimitry Andric if (!Next) { 8804eeddc0SDimitry Andric assert(!History.empty()); 8904eeddc0SDimitry Andric // Found a marker, we have gone up a level. 9004eeddc0SDimitry Andric History.pop_back(); 9104eeddc0SDimitry Andric continue; 9204eeddc0SDimitry Andric } 9304eeddc0SDimitry Andric QualType NextTy = Next->getType(); 9404eeddc0SDimitry Andric 9504eeddc0SDimitry Andric if (!Visited.insert(NextTy).second) 9604eeddc0SDimitry Andric continue; 9704eeddc0SDimitry Andric 9804eeddc0SDimitry Andric auto EmitHistory = [&]() { 9904eeddc0SDimitry Andric // The first element is always nullptr. 10004eeddc0SDimitry Andric for (uint64_t Index = 1; Index < History.size(); ++Index) { 101*0fca6ea1SDimitry Andric DiagIfDeviceCode(History[Index]->getLocation(), 10204eeddc0SDimitry Andric diag::note_within_field_of_type) 10304eeddc0SDimitry Andric << History[Index]->getType(); 10404eeddc0SDimitry Andric } 10504eeddc0SDimitry Andric }; 10604eeddc0SDimitry Andric 10704eeddc0SDimitry Andric if (Check(NextTy, Next)) { 10804eeddc0SDimitry Andric if (NeedToEmitNotes) 10904eeddc0SDimitry Andric EmitHistory(); 11004eeddc0SDimitry Andric NeedToEmitNotes = false; 11104eeddc0SDimitry Andric } 11204eeddc0SDimitry Andric 11304eeddc0SDimitry Andric // In case pointer/array/reference type is met get pointee type, then 11404eeddc0SDimitry Andric // proceed with that type. 11504eeddc0SDimitry Andric while (NextTy->isAnyPointerType() || NextTy->isArrayType() || 11604eeddc0SDimitry Andric NextTy->isReferenceType()) { 11704eeddc0SDimitry Andric if (NextTy->isArrayType()) 11804eeddc0SDimitry Andric NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0}; 11904eeddc0SDimitry Andric else 12004eeddc0SDimitry Andric NextTy = NextTy->getPointeeType(); 12104eeddc0SDimitry Andric if (Check(NextTy, Next)) { 12204eeddc0SDimitry Andric if (NeedToEmitNotes) 12304eeddc0SDimitry Andric EmitHistory(); 12404eeddc0SDimitry Andric NeedToEmitNotes = false; 12504eeddc0SDimitry Andric } 12604eeddc0SDimitry Andric } 12704eeddc0SDimitry Andric 12804eeddc0SDimitry Andric if (const auto *RecDecl = NextTy->getAsRecordDecl()) { 12904eeddc0SDimitry Andric if (auto *NextFD = dyn_cast<FieldDecl>(Next)) 13004eeddc0SDimitry Andric History.push_back(NextFD); 13104eeddc0SDimitry Andric // When nullptr is discovered, this means we've gone back up a level, so 13204eeddc0SDimitry Andric // the history should be cleaned. 13304eeddc0SDimitry Andric StackForRecursion.push_back(nullptr); 13404eeddc0SDimitry Andric llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion)); 13504eeddc0SDimitry Andric } 13604eeddc0SDimitry Andric } while (!StackForRecursion.empty()); 13704eeddc0SDimitry Andric } 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric ExprResult SemaSYCL::BuildUniqueStableNameExpr(SourceLocation OpLoc, 140*0fca6ea1SDimitry Andric SourceLocation LParen, 141*0fca6ea1SDimitry Andric SourceLocation RParen, 142*0fca6ea1SDimitry Andric TypeSourceInfo *TSI) { 143*0fca6ea1SDimitry Andric return SYCLUniqueStableNameExpr::Create(getASTContext(), OpLoc, LParen, 144*0fca6ea1SDimitry Andric RParen, TSI); 145*0fca6ea1SDimitry Andric } 146*0fca6ea1SDimitry Andric 147*0fca6ea1SDimitry Andric ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc, 148*0fca6ea1SDimitry Andric SourceLocation LParen, 149*0fca6ea1SDimitry Andric SourceLocation RParen, 150*0fca6ea1SDimitry Andric ParsedType ParsedTy) { 151*0fca6ea1SDimitry Andric TypeSourceInfo *TSI = nullptr; 152*0fca6ea1SDimitry Andric QualType Ty = SemaRef.GetTypeFromParser(ParsedTy, &TSI); 153*0fca6ea1SDimitry Andric 154*0fca6ea1SDimitry Andric if (Ty.isNull()) 155*0fca6ea1SDimitry Andric return ExprError(); 156*0fca6ea1SDimitry Andric if (!TSI) 157*0fca6ea1SDimitry Andric TSI = getASTContext().getTrivialTypeSourceInfo(Ty, LParen); 158*0fca6ea1SDimitry Andric 159*0fca6ea1SDimitry Andric return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); 160*0fca6ea1SDimitry Andric } 161*0fca6ea1SDimitry Andric 162*0fca6ea1SDimitry Andric void SemaSYCL::handleKernelAttr(Decl *D, const ParsedAttr &AL) { 163*0fca6ea1SDimitry Andric // The 'sycl_kernel' attribute applies only to function templates. 164*0fca6ea1SDimitry Andric const auto *FD = cast<FunctionDecl>(D); 165*0fca6ea1SDimitry Andric const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate(); 166*0fca6ea1SDimitry Andric assert(FT && "Function template is expected"); 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric // Function template must have at least two template parameters. 169*0fca6ea1SDimitry Andric const TemplateParameterList *TL = FT->getTemplateParameters(); 170*0fca6ea1SDimitry Andric if (TL->size() < 2) { 171*0fca6ea1SDimitry Andric Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params); 172*0fca6ea1SDimitry Andric return; 173*0fca6ea1SDimitry Andric } 174*0fca6ea1SDimitry Andric 175*0fca6ea1SDimitry Andric // Template parameters must be typenames. 176*0fca6ea1SDimitry Andric for (unsigned I = 0; I < 2; ++I) { 177*0fca6ea1SDimitry Andric const NamedDecl *TParam = TL->getParam(I); 178*0fca6ea1SDimitry Andric if (isa<NonTypeTemplateParmDecl>(TParam)) { 179*0fca6ea1SDimitry Andric Diag(FT->getLocation(), 180*0fca6ea1SDimitry Andric diag::warn_sycl_kernel_invalid_template_param_type); 181*0fca6ea1SDimitry Andric return; 182*0fca6ea1SDimitry Andric } 183*0fca6ea1SDimitry Andric } 184*0fca6ea1SDimitry Andric 185*0fca6ea1SDimitry Andric // Function must have at least one argument. 186*0fca6ea1SDimitry Andric if (getFunctionOrMethodNumParams(D) != 1) { 187*0fca6ea1SDimitry Andric Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params); 188*0fca6ea1SDimitry Andric return; 189*0fca6ea1SDimitry Andric } 190*0fca6ea1SDimitry Andric 191*0fca6ea1SDimitry Andric // Function must return void. 192*0fca6ea1SDimitry Andric QualType RetTy = getFunctionOrMethodResultType(D); 193*0fca6ea1SDimitry Andric if (!RetTy->isVoidType()) { 194*0fca6ea1SDimitry Andric Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type); 195*0fca6ea1SDimitry Andric return; 196*0fca6ea1SDimitry Andric } 197*0fca6ea1SDimitry Andric 198*0fca6ea1SDimitry Andric handleSimpleAttribute<SYCLKernelAttr>(*this, D, AL); 199*0fca6ea1SDimitry Andric } 200