xref: /freebsd/contrib/llvm-project/clang/lib/Sema/SemaSYCL.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
SemaSYCL(Sema & S)24*0fca6ea1SDimitry Andric SemaSYCL::SemaSYCL(Sema &S) : SemaBase(S) {}
25*0fca6ea1SDimitry Andric 
DiagIfDeviceCode(SourceLocation Loc,unsigned DiagID)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 
isZeroSizedArray(SemaSYCL & S,QualType Ty)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 
deepTypeCheckForDevice(SourceLocation UsedAt,llvm::DenseSet<QualType> Visited,ValueDecl * DeclToCheck)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 
BuildUniqueStableNameExpr(SourceLocation OpLoc,SourceLocation LParen,SourceLocation RParen,TypeSourceInfo * TSI)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 
ActOnUniqueStableNameExpr(SourceLocation OpLoc,SourceLocation LParen,SourceLocation RParen,ParsedType ParsedTy)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 
handleKernelAttr(Decl * D,const ParsedAttr & AL)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