clang 23.0.0git
SemaSYCL.cpp
Go to the documentation of this file.
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/Sema/SemaSYCL.h"
12#include "TreeTransform.h"
13#include "clang/AST/Mangle.h"
15#include "clang/AST/StmtSYCL.h"
18#include "clang/Sema/Attr.h"
20#include "clang/Sema/Sema.h"
21
22using namespace clang;
23
24// -----------------------------------------------------------------------------
25// SYCL device specific diagnostics implementation
26// -----------------------------------------------------------------------------
27
29
31 unsigned DiagID) {
32 assert(getLangOpts().SYCLIsDevice &&
33 "Device diagnostics Should only be issued during device compilation");
34 SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop;
35 FunctionDecl *FD = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true);
36 if (FD) {
37 Sema::FunctionEmissionStatus FES = SemaRef.getEmissionStatus(FD);
38 switch (FES) {
40 DiagKind = SemaDiagnosticBuilder::K_ImmediateWithCallStack;
41 break;
44 DiagKind = SemaDiagnosticBuilder::K_Deferred;
45 break;
47 llvm_unreachable("OMPDiscarded unexpected in SYCL device compilation");
49 llvm_unreachable("CUDADiscarded unexpected in SYCL device compilation");
50 }
51 }
52 return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, SemaRef);
53}
54
55static bool isZeroSizedArray(SemaSYCL &S, QualType Ty) {
56 if (const auto *CAT = S.getASTContext().getAsConstantArrayType(Ty))
57 return CAT->isZeroSize();
58 return false;
59}
60
62 llvm::DenseSet<QualType> Visited,
63 ValueDecl *DeclToCheck) {
64 assert(getLangOpts().SYCLIsDevice &&
65 "Should only be called during SYCL compilation");
66 // Emit notes only for the first discovered declaration of unsupported type
67 // to avoid mess of notes. This flag is to track that error already happened.
68 bool NeedToEmitNotes = true;
69
70 auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
71 bool ErrorFound = false;
72 if (isZeroSizedArray(*this, TypeToCheck)) {
73 DiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1;
74 ErrorFound = true;
75 }
76 // Checks for other types can also be done here.
77 if (ErrorFound) {
78 if (NeedToEmitNotes) {
79 if (auto *FD = dyn_cast<FieldDecl>(D))
80 DiagIfDeviceCode(FD->getLocation(),
81 diag::note_illegal_field_declared_here)
82 << FD->getType()->isPointerType() << FD->getType();
83 else
84 DiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
85 }
86 }
87
88 return ErrorFound;
89 };
90
91 // In case we have a Record used do the DFS for a bad field.
92 SmallVector<const ValueDecl *, 4> StackForRecursion;
93 StackForRecursion.push_back(DeclToCheck);
94
95 // While doing DFS save how we get there to emit a nice set of notes.
97 History.push_back(nullptr);
98
99 do {
100 const ValueDecl *Next = StackForRecursion.pop_back_val();
101 if (!Next) {
102 assert(!History.empty());
103 // Found a marker, we have gone up a level.
104 History.pop_back();
105 continue;
106 }
107 QualType NextTy = Next->getType();
108
109 if (!Visited.insert(NextTy).second)
110 continue;
111
112 auto EmitHistory = [&]() {
113 // The first element is always nullptr.
114 for (uint64_t Index = 1; Index < History.size(); ++Index) {
115 DiagIfDeviceCode(History[Index]->getLocation(),
116 diag::note_within_field_of_type)
117 << History[Index]->getType();
118 }
119 };
120
121 if (Check(NextTy, Next)) {
122 if (NeedToEmitNotes)
123 EmitHistory();
124 NeedToEmitNotes = false;
125 }
126
127 // In case pointer/array/reference type is met get pointee type, then
128 // proceed with that type.
129 while (NextTy->isAnyPointerType() || NextTy->isArrayType() ||
130 NextTy->isReferenceType()) {
131 if (NextTy->isArrayType())
132 NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0};
133 else
134 NextTy = NextTy->getPointeeType();
135 if (Check(NextTy, Next)) {
136 if (NeedToEmitNotes)
137 EmitHistory();
138 NeedToEmitNotes = false;
139 }
140 }
141
142 if (const auto *RecDecl = NextTy->getAsRecordDecl()) {
143 if (auto *NextFD = dyn_cast<FieldDecl>(Next))
144 History.push_back(NextFD);
145 // When nullptr is discovered, this means we've gone back up a level, so
146 // the history should be cleaned.
147 StackForRecursion.push_back(nullptr);
148 llvm::append_range(StackForRecursion, RecDecl->fields());
149 }
150 } while (!StackForRecursion.empty());
151}
152
154 SourceLocation LParen,
155 SourceLocation RParen,
156 TypeSourceInfo *TSI) {
157 return SYCLUniqueStableNameExpr::Create(getASTContext(), OpLoc, LParen,
158 RParen, TSI);
159}
160
162 SourceLocation LParen,
163 SourceLocation RParen,
164 ParsedType ParsedTy) {
165 TypeSourceInfo *TSI = nullptr;
166 QualType Ty = SemaRef.GetTypeFromParser(ParsedTy, &TSI);
167
168 if (Ty.isNull())
169 return ExprError();
170 if (!TSI)
171 TSI = getASTContext().getTrivialTypeSourceInfo(Ty, LParen);
172
173 return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
174}
175
177 // The 'sycl_kernel' attribute applies only to function templates.
178 const auto *FD = cast<FunctionDecl>(D);
179 const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate();
180 assert(FT && "Function template is expected");
181
182 // Function template must have at least two template parameters.
184 if (TL->size() < 2) {
185 Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params);
186 return;
187 }
188
189 // Template parameters must be typenames.
190 for (unsigned I = 0; I < 2; ++I) {
191 const NamedDecl *TParam = TL->getParam(I);
192 if (isa<NonTypeTemplateParmDecl>(TParam)) {
193 Diag(FT->getLocation(),
194 diag::warn_sycl_kernel_invalid_template_param_type);
195 return;
196 }
197 }
198
199 // Function must have at least one argument.
200 if (getFunctionOrMethodNumParams(D) != 1) {
201 Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
202 return;
203 }
204
205 // Function must return void.
207 if (!RetTy->isVoidType()) {
208 Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type);
209 return;
210 }
211
213}
214
216 ParsedType PT = AL.getTypeArg();
217 TypeSourceInfo *TSI = nullptr;
218 (void)SemaRef.GetTypeFromParser(PT, &TSI);
219 assert(TSI && "no type source info for attribute argument");
220 D->addAttr(::new (SemaRef.Context)
221 SYCLKernelEntryPointAttr(SemaRef.Context, AL, TSI));
222}
223
225 assert(getLangOpts().SYCLIsDevice &&
226 "Should only be called during SYCL device compilation");
227
228 // Function declarations with the sycl_kernel_entry_point attribute cannot
229 // be ODR-used in a potentially evaluated context.
230 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
231 if (const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>()) {
232 if (SemaRef.currentEvaluationContext().isPotentiallyEvaluated()) {
233 DiagIfDeviceCode(Loc, diag::err_sycl_entry_point_device_use)
234 << FD << SKEPAttr;
235 DiagIfDeviceCode(SKEPAttr->getLocation(), diag::note_attribute) << FD;
236 }
237 }
238 }
239}
240
241// Given a potentially qualified type, SourceLocationForUserDeclaredType()
242// returns the source location of the canonical declaration of the unqualified
243// desugared user declared type, if any. For non-user declared types, an
244// invalid source location is returned. The intended usage of this function
245// is to identify an appropriate source location, if any, for a
246// "entity declared here" diagnostic note.
248 SourceLocation Loc;
249 const Type *T = QT->getUnqualifiedDesugaredType();
250 if (const TagType *TT = dyn_cast<TagType>(T))
251 Loc = TT->getDecl()->getLocation();
252 else if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(T))
253 Loc = ObjCIT->getDecl()->getLocation();
254 return Loc;
255}
256
258 QualType KernelName) {
259 assert(!KernelName->isDependentType());
260
261 if (!KernelName->isStructureOrClassType()) {
262 // SYCL 2020 section 5.2, "Naming of kernels", only requires that the
263 // kernel name be a C++ typename. However, the definition of "kernel name"
264 // in the glossary states that a kernel name is a class type. Neither
265 // section explicitly states whether the kernel name type can be
266 // cv-qualified. For now, kernel name types are required to be class types
267 // and that they may be cv-qualified. The following issue requests
268 // clarification from the SYCL WG.
269 // https://github.com/KhronosGroup/SYCL-Docs/issues/568
270 S.Diag(Loc, diag::warn_sycl_kernel_name_not_a_class_type) << KernelName;
271 SourceLocation DeclTypeLoc = SourceLocationForUserDeclaredType(KernelName);
272 if (DeclTypeLoc.isValid())
273 S.Diag(DeclTypeLoc, diag::note_entity_declared_at) << KernelName;
274 return true;
275 }
276
277 return false;
278}
279
281 const auto *SEAttr = FD->getAttr<SYCLExternalAttr>();
282 assert(SEAttr && "Missing sycl_external attribute");
283 if (!FD->isInvalidDecl() && !FD->isTemplated()) {
284 if (!FD->isExternallyVisible())
287 Diag(SEAttr->getLocation(), diag::err_sycl_external_invalid_linkage)
288 << SEAttr;
289 }
290 if (FD->isDeletedAsWritten()) {
291 Diag(SEAttr->getLocation(),
292 diag::err_sycl_external_invalid_deleted_function)
293 << SEAttr;
294 }
295}
296
298 // Ensure that all attributes present on the declaration are consistent
299 // and warn about any redundant ones.
300 SYCLKernelEntryPointAttr *SKEPAttr = nullptr;
301 for (auto *SAI : FD->specific_attrs<SYCLKernelEntryPointAttr>()) {
302 if (!SKEPAttr) {
303 SKEPAttr = SAI;
304 continue;
305 }
306 if (!getASTContext().hasSameType(SAI->getKernelName(),
307 SKEPAttr->getKernelName())) {
308 Diag(SAI->getLocation(), diag::err_sycl_entry_point_invalid_redeclaration)
309 << SKEPAttr << SAI->getKernelName() << SKEPAttr->getKernelName();
310 Diag(SKEPAttr->getLocation(), diag::note_previous_attribute);
311 SAI->setInvalidAttr();
312 } else {
313 Diag(SAI->getLocation(),
314 diag::warn_sycl_entry_point_redundant_declaration)
315 << SAI;
316 Diag(SKEPAttr->getLocation(), diag::note_previous_attribute);
317 }
318 }
319 assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
320
321 // Ensure the kernel name type is valid.
322 if (!SKEPAttr->getKernelName()->isDependentType() &&
323 CheckSYCLKernelName(SemaRef, SKEPAttr->getLocation(),
324 SKEPAttr->getKernelName()))
325 SKEPAttr->setInvalidAttr();
326
327 // Ensure that an attribute present on the previous declaration
328 // matches the one on this declaration.
329 FunctionDecl *PrevFD = FD->getPreviousDecl();
330 if (PrevFD && !PrevFD->isInvalidDecl()) {
331 const auto *PrevSKEPAttr = PrevFD->getAttr<SYCLKernelEntryPointAttr>();
332 if (PrevSKEPAttr && !PrevSKEPAttr->isInvalidAttr()) {
333 if (!getASTContext().hasSameType(SKEPAttr->getKernelName(),
334 PrevSKEPAttr->getKernelName())) {
335 Diag(SKEPAttr->getLocation(),
336 diag::err_sycl_entry_point_invalid_redeclaration)
337 << SKEPAttr << SKEPAttr->getKernelName()
338 << PrevSKEPAttr->getKernelName();
339 Diag(PrevSKEPAttr->getLocation(), diag::note_previous_decl) << PrevFD;
340 SKEPAttr->setInvalidAttr();
341 }
342 }
343 }
344
345 if (isa<CXXConstructorDecl>(FD)) {
346 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
347 << SKEPAttr << diag::InvalidSKEPReason::Constructor;
348 SKEPAttr->setInvalidAttr();
349 }
350 if (isa<CXXDestructorDecl>(FD)) {
351 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
352 << SKEPAttr << diag::InvalidSKEPReason::Destructor;
353 SKEPAttr->setInvalidAttr();
354 }
355 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
356 if (MD->isExplicitObjectMemberFunction()) {
357 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
358 << SKEPAttr << diag::InvalidSKEPReason::ExplicitObjectFn;
359 SKEPAttr->setInvalidAttr();
360 }
361 }
362
363 if (FD->isVariadic()) {
364 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
365 << SKEPAttr << diag::InvalidSKEPReason::VariadicFn;
366 SKEPAttr->setInvalidAttr();
367 }
368
369 if (FD->isDefaulted()) {
370 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
371 << SKEPAttr << diag::InvalidSKEPReason::DefaultedFn;
372 SKEPAttr->setInvalidAttr();
373 } else if (FD->isDeleted()) {
374 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
375 << SKEPAttr << diag::InvalidSKEPReason::DeletedFn;
376 SKEPAttr->setInvalidAttr();
377 }
378
379 if (FD->isConsteval()) {
380 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
381 << SKEPAttr << diag::InvalidSKEPReason::ConstevalFn;
382 SKEPAttr->setInvalidAttr();
383 } else if (FD->isConstexpr()) {
384 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
385 << SKEPAttr << diag::InvalidSKEPReason::ConstexprFn;
386 SKEPAttr->setInvalidAttr();
387 }
388
389 if (FD->isNoReturn()) {
390 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
391 << SKEPAttr << diag::InvalidSKEPReason::NoreturnFn;
392 SKEPAttr->setInvalidAttr();
393 }
394
395 if (FD->getReturnType()->isUndeducedType()) {
396 Diag(SKEPAttr->getLocation(),
397 diag::err_sycl_entry_point_deduced_return_type)
398 << SKEPAttr;
399 SKEPAttr->setInvalidAttr();
400 } else if (!FD->getReturnType()->isDependentType() &&
401 !FD->getReturnType()->isVoidType()) {
402 Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_return_type)
403 << SKEPAttr;
404 SKEPAttr->setInvalidAttr();
405 }
406
407 if (!FD->isInvalidDecl() && !FD->isTemplated() &&
408 !SKEPAttr->isInvalidAttr()) {
409 const SYCLKernelInfo *SKI =
410 getASTContext().findSYCLKernelInfo(SKEPAttr->getKernelName());
411 if (SKI) {
413 // FIXME: This diagnostic should include the origin of the kernel
414 // FIXME: names; not just the locations of the conflicting declarations.
415 Diag(FD->getLocation(), diag::err_sycl_kernel_name_conflict)
416 << SKEPAttr;
418 diag::note_previous_declaration);
419 SKEPAttr->setInvalidAttr();
420 }
421 } else {
423 }
424 }
425}
426
428 QualType KNT) {
429 // The current context must be the function definition context to ensure
430 // that name lookup is performed within the correct scope.
431 assert(SemaRef.CurContext == FD && "The current declaration context does not "
432 "match the requested function context");
433
434 // An appropriate source location is required to emit diagnostics if
435 // lookup fails to produce an overload set. The desired location is the
436 // start of the function body, but that is not yet available since the
437 // body of the function has not yet been set when this function is called.
438 // The general location of the function is used instead.
439 SourceLocation Loc = FD->getLocation();
440
441 ASTContext &Ctx = SemaRef.getASTContext();
442 IdentifierInfo &SYCLKernelLaunchID =
443 Ctx.Idents.get("sycl_kernel_launch", tok::TokenKind::identifier);
444
445 // Establish a code synthesis context for the implicit name lookup of
446 // a template named 'sycl_kernel_launch'. In the event of an error, this
447 // ensures an appropriate diagnostic note is issued to explain why the
448 // lookup was performed.
451 CSC.Entity = FD;
453
454 // Perform ordinary name lookup for a function or variable template that
455 // accepts a single type template argument.
456 LookupResult Result(SemaRef, &SYCLKernelLaunchID, Loc,
458 CXXScopeSpec EmptySS;
459 if (SemaRef.LookupTemplateName(Result, SemaRef.getCurScope(), EmptySS,
460 /*ObjectType*/ QualType(),
461 /*EnteringContext*/ false,
463 return ExprError();
464 if (Result.isAmbiguous())
465 return ExprError();
466
467 TemplateArgumentListInfo TALI{Loc, Loc};
470 SemaRef.getTrivialTemplateArgumentLoc(KNTA, QualType(), Loc);
471 TALI.addArgument(TAL);
472
473 ExprResult IdExpr;
474 if (SemaRef.isPotentialImplicitMemberAccess(EmptySS, Result,
475 /*IsAddressOfOperand*/ false)) {
476 // The lookup result allows for a possible implicit member access that
477 // would require an implicit or explicit 'this' argument.
478 IdExpr = SemaRef.BuildPossibleImplicitMemberExpr(
479 EmptySS, SourceLocation(), Result, &TALI, SemaRef.getCurScope());
480 } else {
481 IdExpr = SemaRef.BuildTemplateIdExpr(EmptySS, SourceLocation(), Result,
482 /*RequiresADL*/ true, &TALI);
483 }
484
485 // The resulting expression may be invalid if, for example, 'FD' is a
486 // non-static member function and sycl_kernel_launch lookup selects a
487 // member function (which would require a 'this' argument which is
488 // not available).
489 if (IdExpr.isInvalid())
490 return ExprError();
491
492 return IdExpr;
493}
494
495namespace {
496
497// Constructs the arguments to be passed for the SYCL kernel launch call.
498// The first argument is a string literal that contains the SYCL kernel
499// name. The remaining arguments are the parameters of 'FD' passed as
500// move-elligible xvalues. Returns true on error and false otherwise.
501bool BuildSYCLKernelLaunchCallArgs(Sema &SemaRef, FunctionDecl *FD,
502 const SYCLKernelInfo *SKI,
504 SourceLocation Loc) {
505 // The current context must be the function definition context to ensure
506 // that parameter references occur within the correct scope.
507 assert(SemaRef.CurContext == FD && "The current declaration context does not "
508 "match the requested function context");
509
510 // Prepare a string literal that contains the kernel name.
511 ASTContext &Ctx = SemaRef.getASTContext();
512 const std::string &KernelName = SKI->GetKernelName();
513 QualType KernelNameCharTy = Ctx.CharTy.withConst();
514 llvm::APInt KernelNameSize(Ctx.getTypeSize(Ctx.getSizeType()),
515 KernelName.size() + 1);
516 QualType KernelNameArrayTy = Ctx.getConstantArrayType(
517 KernelNameCharTy, KernelNameSize, nullptr, ArraySizeModifier::Normal, 0);
518 Expr *KernelNameExpr =
520 /*Pascal*/ false, KernelNameArrayTy, Loc);
521 Args.push_back(KernelNameExpr);
522
523 // Forward all parameters of 'FD' to the SYCL kernel launch function as if
524 // by std::move().
525 for (ParmVarDecl *PVD : FD->parameters()) {
526 QualType ParamType = PVD->getOriginalType().getNonReferenceType();
527 ExprResult E = SemaRef.BuildDeclRefExpr(PVD, ParamType, VK_LValue, Loc);
528 if (E.isInvalid())
529 return true;
530 if (!PVD->getType()->isLValueReferenceType())
531 E = ImplicitCastExpr::Create(SemaRef.Context, E.get()->getType(), CK_NoOp,
532 E.get(), nullptr, VK_XValue,
534 if (E.isInvalid())
535 return true;
536 Args.push_back(E.get());
537 }
538
539 return false;
540}
541
542// Constructs the SYCL kernel launch call.
543StmtResult BuildSYCLKernelLaunchCallStmt(Sema &SemaRef, FunctionDecl *FD,
544 const SYCLKernelInfo *SKI,
545 Expr *IdExpr, SourceLocation Loc) {
547 // IdExpr may be null if name lookup failed.
548 if (IdExpr) {
550
551 // Establish a code synthesis context for construction of the arguments
552 // for the implicit call to 'sycl_kernel_launch'.
553 {
556 CSC.Entity = FD;
557 Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
558
559 if (BuildSYCLKernelLaunchCallArgs(SemaRef, FD, SKI, Args, Loc))
560 return StmtError();
561 }
562
563 // Establish a code synthesis context for the implicit call to
564 // 'sycl_kernel_launch'.
565 {
568 CSC.Entity = FD;
569 CSC.CallArgs = Args.data();
570 CSC.NumCallArgs = Args.size();
571 Sema::ScopedCodeSynthesisContext ScopedCSC(SemaRef, CSC);
572
573 ExprResult LaunchResult =
574 SemaRef.BuildCallExpr(SemaRef.getCurScope(), IdExpr, Loc, Args, Loc);
575 if (LaunchResult.isInvalid())
576 return StmtError();
577
578 Stmts.push_back(SemaRef.MaybeCreateExprWithCleanups(LaunchResult).get());
579 }
580 }
581
582 return CompoundStmt::Create(SemaRef.getASTContext(), Stmts,
583 FPOptionsOverride(), Loc, Loc);
584}
585
586// The body of a function declared with the [[sycl_kernel_entry_point]]
587// attribute is cloned and transformed to substitute references to the original
588// function parameters with references to replacement variables that stand in
589// for SYCL kernel parameters or local variables that reconstitute a decomposed
590// SYCL kernel argument.
591class OutlinedFunctionDeclBodyInstantiator
592 : public TreeTransform<OutlinedFunctionDeclBodyInstantiator> {
593public:
594 using ParmDeclMap = llvm::DenseMap<ParmVarDecl *, VarDecl *>;
595
596 OutlinedFunctionDeclBodyInstantiator(Sema &S, ParmDeclMap &M,
597 FunctionDecl *FD)
598 : TreeTransform<OutlinedFunctionDeclBodyInstantiator>(S), SemaRef(S),
599 MapRef(M), FD(FD) {}
600
601 // A new set of AST nodes is always required.
602 bool AlwaysRebuild() { return true; }
603
604 // Transform ParmVarDecl references to the supplied replacement variables.
605 ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) {
606 const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl());
607 if (PVD) {
608 ParmDeclMap::iterator I = MapRef.find(PVD);
609 if (I != MapRef.end()) {
610 VarDecl *VD = I->second;
611 assert(SemaRef.getASTContext().hasSameUnqualifiedType(PVD->getType(),
612 VD->getType()));
613 assert(!VD->getType().isMoreQualifiedThan(PVD->getType(),
614 SemaRef.getASTContext()));
615 VD->setIsUsed();
616 return DeclRefExpr::Create(
617 SemaRef.getASTContext(), DRE->getQualifierLoc(),
618 DRE->getTemplateKeywordLoc(), VD, false, DRE->getNameInfo(),
619 DRE->getType(), DRE->getValueKind());
620 }
621 }
622 return DRE;
623 }
624
625 // Diagnose CXXThisExpr in a potentially evaluated expression.
626 ExprResult TransformCXXThisExpr(CXXThisExpr *CTE) {
628 SemaRef.Diag(CTE->getExprLoc(), diag::err_sycl_entry_point_invalid_this)
629 << (CTE->isImplicitCXXThis() ? /* implicit */ 1 : /* empty */ 0)
630 << FD->getAttr<SYCLKernelEntryPointAttr>();
631 }
632 return CTE;
633 }
634
635private:
636 Sema &SemaRef;
637 ParmDeclMap &MapRef;
638 FunctionDecl *FD;
639};
640
641OutlinedFunctionDecl *BuildSYCLKernelEntryPointOutline(Sema &SemaRef,
642 FunctionDecl *FD,
643 CompoundStmt *Body) {
644 using ParmDeclMap = OutlinedFunctionDeclBodyInstantiator::ParmDeclMap;
645 ParmDeclMap ParmMap;
646
648 SemaRef.getASTContext(), FD, FD->getNumParams());
649 unsigned i = 0;
650 for (ParmVarDecl *PVD : FD->parameters()) {
652 SemaRef.getASTContext(), OFD, SourceLocation(), PVD->getIdentifier(),
654 OFD->setParam(i, IPD);
655 ParmMap[PVD] = IPD;
656 ++i;
657 }
658
659 OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap,
660 FD);
661 Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get();
662 OFD->setBody(OFDBody);
663 OFD->setNothrow();
664
665 return OFD;
666}
667
668} // unnamed namespace
669
671 CompoundStmt *Body,
672 Expr *LaunchIdExpr) {
673 assert(!FD->isInvalidDecl());
674 assert(!FD->isTemplated());
675 assert(FD->hasPrototype());
676 // The current context must be the function definition context to ensure
677 // that name lookup and parameter and local variable creation are performed
678 // within the correct scope.
679 assert(SemaRef.CurContext == FD && "The current declaration context does not "
680 "match the requested function context");
681
682 const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
683 assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
684 assert(!SKEPAttr->isInvalidAttr() &&
685 "sycl_kernel_entry_point attribute is invalid");
686
687 // Ensure that the kernel name was previously registered and that the
688 // stored declaration matches.
689 const SYCLKernelInfo &SKI =
690 getASTContext().getSYCLKernelInfo(SKEPAttr->getKernelName());
692 "SYCL kernel name conflict");
693
694 // Build the outline of the synthesized device entry point function.
696 BuildSYCLKernelEntryPointOutline(SemaRef, FD, Body);
697 assert(OFD);
698
699 // Build the host kernel launch statement. An appropriate source location
700 // is required to emit diagnostics.
701 SourceLocation Loc = Body->getLBracLoc();
702 StmtResult LaunchResult =
703 BuildSYCLKernelLaunchCallStmt(SemaRef, FD, &SKI, LaunchIdExpr, Loc);
704 if (LaunchResult.isInvalid())
705 return StmtError();
706
707 Stmt *NewBody =
708 new (getASTContext()) SYCLKernelCallStmt(Body, LaunchResult.get(), OFD);
709
710 return NewBody;
711}
712
714 Expr *LaunchIdExpr) {
715 return UnresolvedSYCLKernelCallStmt::Create(SemaRef.getASTContext(), Body,
716 LaunchIdExpr);
717}
Defines the Diagnostic-related interfaces.
FormatToken * Next
The next token in the unwrapped line.
This file declares types used to describe SYCL kernels.
static bool isZeroSizedArray(const ConstantArrayType *CAT)
Definition SemaHLSL.cpp:338
static SourceLocation SourceLocationForUserDeclaredType(QualType QT)
Definition SemaSYCL.cpp:247
static bool CheckSYCLKernelName(Sema &S, SourceLocation Loc, QualType KernelName)
Definition SemaSYCL.cpp:257
This file declares semantic analysis for SYCL constructs.
This file defines SYCL AST classes used to represent calls to SYCL kernels.
Allows QualTypes to be sorted and hence used in maps and sets.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:226
const ConstantArrayType * getAsConstantArrayType(QualType T) const
IdentifierTable & Idents
Definition ASTContext.h:797
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc=SourceLocation()) const
Allocate a TypeSourceInfo where all locations have been initialized to a given location,...
CanQualType CharTy
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
void registerSYCLEntryPointFunction(FunctionDecl *FD)
Generates and stores SYCL kernel metadata for the provided SYCL kernel entry point function.
const SYCLKernelInfo & getSYCLKernelInfo(QualType T) const
Given a type used as a SYCL kernel name, returns a reference to the metadata generated from the corre...
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
static bool hasSameUnqualifiedType(QualType T1, QualType T2)
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
const SYCLKernelInfo * findSYCLKernelInfo(QualType T) const
Returns a pointer to the metadata generated from the corresponding SYCLkernel entry point if the prov...
PtrTy get() const
Definition Ownership.h:171
bool isInvalid() const
Definition Ownership.h:167
Represents a C++ nested-name-specifier or a global scope specifier.
Definition DeclSpec.h:74
QualType withConst() const
Retrieves a version of this type with const applied.
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1732
SourceLocation getLBracLoc() const
Definition Stmt.h:1849
static CompoundStmt * Create(const ASTContext &C, ArrayRef< Stmt * > Stmts, FPOptionsOverride FPFeatures, SourceLocation LB, SourceLocation RB)
Definition Stmt.cpp:399
DeclarationNameInfo getNameInfo() const
Definition Expr.h:1345
SourceLocation getTemplateKeywordLoc() const
Retrieve the location of the template keyword preceding this name, if any.
Definition Expr.h:1400
static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD=nullptr, const TemplateArgumentListInfo *TemplateArgs=nullptr, NonOdrUseReason NOUR=NOUR_None)
Definition Expr.cpp:488
NestedNameSpecifierLoc getQualifierLoc() const
If the name was qualified, retrieves the nested-name-specifier that precedes the name,...
Definition Expr.h:1366
ValueDecl * getDecl()
Definition Expr.h:1341
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
T * getAttr() const
Definition DeclBase.h:573
void addAttr(Attr *A)
bool isTemplated() const
Determine whether this declaration is a templated entity (whether it is.
Definition DeclBase.cpp:308
bool isInvalidDecl() const
Definition DeclBase.h:588
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition DeclBase.h:559
SourceLocation getLocation() const
Definition DeclBase.h:439
void setIsUsed()
Set whether the declaration is used, in the sense of odr-use.
Definition DeclBase.h:608
This represents one expression.
Definition Expr.h:112
bool isImplicitCXXThis() const
Whether this expression is an implicit reference to 'this' in C++.
Definition Expr.cpp:3295
ExprValueKind getValueKind() const
getValueKind - The value kind that this expression produces.
Definition Expr.h:447
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:277
QualType getType() const
Definition Expr.h:144
Represents difference between two FPOptions values.
Represents a function declaration or definition.
Definition Decl.h:2000
bool isFunctionTemplateSpecialization() const
Determine whether this function is a function template specialization.
Definition Decl.cpp:4206
bool isNoReturn() const
Determines whether this function is known to be 'noreturn', through an attribute on its declaration o...
Definition Decl.cpp:3652
QualType getReturnType() const
Definition Decl.h:2845
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2774
bool hasPrototype() const
Whether this function has a prototype, either because one was explicitly written or because it was "i...
Definition Decl.h:2443
FunctionTemplateSpecializationInfo * getTemplateSpecializationInfo() const
If this function is actually a function template specialization, retrieve information about this func...
Definition Decl.cpp:4324
bool isVariadic() const
Whether this function is variadic.
Definition Decl.cpp:3134
bool isDeleted() const
Whether this function has been deleted.
Definition Decl.h:2540
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
Definition Decl.h:2470
bool isDeletedAsWritten() const
Definition Decl.h:2544
bool isDefaulted() const
Whether this function is defaulted.
Definition Decl.h:2385
bool isConsteval() const
Definition Decl.h:2482
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition Decl.cpp:3827
FunctionDecl * getPreviousDecl()
Return the previous declaration of this declaration or NULL if this is the first declaration.
Declaration of a template function.
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
static ImplicitCastExpr * Create(const ASTContext &Context, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind Cat, FPOptionsOverride FPO)
Definition Expr.cpp:2073
static ImplicitParamDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, ImplicitParamKind ParamKind)
Create implicit parameter.
Definition Decl.cpp:5603
Represents the results of name lookup.
Definition Lookup.h:147
This represents a decl that may have a name.
Definition Decl.h:274
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:295
bool isExternallyVisible() const
Definition Decl.h:433
Represents a partial function definition.
Definition Decl.h:4881
static OutlinedFunctionDecl * Create(ASTContext &C, DeclContext *DC, unsigned NumParams)
Definition Decl.cpp:5659
void setNothrow(bool Nothrow=true)
Definition Decl.cpp:5679
void setParam(unsigned i, ImplicitParamDecl *P)
Definition Decl.h:4917
Represents a parameter to a function.
Definition Decl.h:1790
ParsedAttr - Represents a syntactic attribute.
Definition ParsedAttr.h:119
const ParsedType & getTypeArg() const
Definition ParsedAttr.h:459
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
bool isMoreQualifiedThan(QualType Other, const ASTContext &Ctx) const
Determine whether this type is more qualified than the other given type, requiring exact equality for...
Definition TypeBase.h:8542
SYCLKernelCallStmt represents the transformation that is applied to the body of a function declared w...
Definition StmtSYCL.h:36
const std::string & GetKernelName() const
const FunctionDecl * getKernelEntryPointDecl() const
static SYCLUniqueStableNameExpr * Create(const ASTContext &Ctx, SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, TypeSourceInfo *TSI)
Definition Expr.cpp:573
A generic diagnostic builder for errors which may or may not be deferred.
Definition SemaBase.h:111
SemaBase(Sema &S)
Definition SemaBase.cpp:7
ASTContext & getASTContext() const
Definition SemaBase.cpp:9
Sema & SemaRef
Definition SemaBase.h:40
const LangOptions & getLangOpts() const
Definition SemaBase.cpp:11
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition SemaBase.cpp:61
StmtResult BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *Body, Expr *LaunchIdExpr)
Builds an UnresolvedSYCLKernelCallStmt to wrap 'Body'.
Definition SemaSYCL.cpp:713
StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body, Expr *LaunchIdExpr)
Builds a SYCLKernelCallStmt to wrap 'Body' and to be used as the body of 'FD'.
Definition SemaSYCL.cpp:670
SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID)
Creates a SemaDiagnosticBuilder that emits the diagnostic if the current context is "used as device c...
Definition SemaSYCL.cpp:30
void CheckSYCLExternalFunctionDecl(FunctionDecl *FD)
Definition SemaSYCL.cpp:280
ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, TypeSourceInfo *TSI)
Definition SemaSYCL.cpp:153
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL)
Definition SemaSYCL.cpp:215
void deepTypeCheckForDevice(SourceLocation UsedAt, llvm::DenseSet< QualType > Visited, ValueDecl *DeclToCheck)
Definition SemaSYCL.cpp:61
void handleKernelAttr(Decl *D, const ParsedAttr &AL)
Definition SemaSYCL.cpp:176
SemaSYCL(Sema &S)
Definition SemaSYCL.cpp:28
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD)
Definition SemaSYCL.cpp:297
void CheckDeviceUseOfDecl(NamedDecl *ND, SourceLocation Loc)
Issues a deferred diagnostic if use of the declaration designated by 'ND' is invalid in a device cont...
Definition SemaSYCL.cpp:224
ExprResult BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD, QualType KernelName)
Builds an expression for the lookup of a 'sycl_kernel_launch' template with 'KernelName' as an explic...
Definition SemaSYCL.cpp:427
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, ParsedType ParsedTy)
Definition SemaSYCL.cpp:161
RAII object to ensure that a code synthesis context is popped on scope exit.
Definition Sema.h:13644
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:868
Scope * getCurScope() const
Retrieve the parser's current scope.
Definition Sema.h:1133
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition Sema.h:9382
FunctionEmissionStatus
Status of the function emission on the CUDA/HIP/OpenMP host/device attrs.
Definition Sema.h:4788
const ExpressionEvaluationContextRecord & currentEvaluationContext() const
Definition Sema.h:6979
ASTContext & Context
Definition Sema.h:1300
ASTContext & getASTContext() const
Definition Sema.h:939
DeclRefExpr * BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS=nullptr)
ExprResult BuildCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig=nullptr, bool IsExecConfig=false, bool AllowRecovery=false)
BuildCallExpr - Handle a call to Fn with the specified array of arguments.
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
Definition Sema.h:1438
Expr * MaybeCreateExprWithCleanups(Expr *SubExpr)
MaybeCreateExprWithCleanups - If the current full-expression requires any cleanups,...
@ TemplateNameIsRequired
Definition Sema.h:11456
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
Stmt - This represents one statement.
Definition Stmt.h:86
static StringLiteral * Create(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, bool Pascal, QualType Ty, ArrayRef< SourceLocation > Locs)
This is the "fully general" constructor that allows representation of strings formed from one or more...
Definition Expr.cpp:1188
A convenient class for passing around template argument information.
void addArgument(const TemplateArgumentLoc &Loc)
Location wrapper for a TemplateArgument.
Represents a template argument.
TemplateParameterList * getTemplateParameters() const
Get the list of template parameters.
Stores a list of template parameters for a TemplateDecl and its derived classes.
NamedDecl * getParam(unsigned Idx)
A semantic tree transformation that allows one to transform one abstract syntax tree into another.
A container of type source information.
Definition TypeBase.h:8359
The base class of the type hierarchy.
Definition TypeBase.h:1839
bool isVoidType() const
Definition TypeBase.h:8991
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isArrayType() const
Definition TypeBase.h:8724
bool isReferenceType() const
Definition TypeBase.h:8649
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition Type.cpp:472
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:753
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition TypeBase.h:2790
bool isUndeducedType() const
Determine whether this type is an undeduced type, meaning that it somehow involves a C++11 'auto' typ...
Definition TypeBase.h:9134
bool isStructureOrClassType() const
Definition Type.cpp:707
bool isAnyPointerType() const
Definition TypeBase.h:8633
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition Type.cpp:654
static UnresolvedSYCLKernelCallStmt * Create(const ASTContext &C, CompoundStmt *CS, Expr *IdExpr)
Definition StmtSYCL.h:120
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
QualType getType() const
Definition Decl.h:723
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
QualType getFunctionOrMethodResultType(const Decl *D)
Definition Attr.h:98
StmtResult StmtError()
Definition Ownership.h:266
@ Result
The result type of a method or function.
Definition TypeBase.h:905
ExprResult ExprError()
Definition Ownership.h:265
void handleSimpleAttribute(SemaBase &S, Decl *D, const AttributeCommonInfo &CI)
Applies the given attribute to the Decl without performing any additional semantic checking.
Definition Attr.h:175
@ VK_XValue
An x-value expression is a reference to an object with independent storage but which can be "moved",...
Definition Specifiers.h:144
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:139
unsigned getFunctionOrMethodNumParams(const Decl *D)
getFunctionOrMethodNumParams - Return number of function or method parameters.
Definition Attr.h:64
bool declaresSameEntity(const Decl *D1, const Decl *D2)
Determine whether two declarations declare the same entity.
Definition DeclBase.h:1288
U cast(CodeGen::Address addr)
Definition Address.h:327
OpaquePtr< QualType > ParsedType
An opaque type for threading parsed type information through the parser.
Definition Ownership.h:230
ActionResult< Expr * > ExprResult
Definition Ownership.h:249
@ Other
Other implicit parameter.
Definition Decl.h:1746
ActionResult< Stmt * > StmtResult
Definition Ownership.h:250
A context in which code is being synthesized (where a source location alone is not sufficient to iden...
Definition Sema.h:13165
enum clang::Sema::CodeSynthesisContext::SynthesisKind Kind
unsigned NumCallArgs
The number of expressions in CallArgs.
Definition Sema.h:13322
const Expr *const * CallArgs
The list of argument expressions in a synthesized call.
Definition Sema.h:13312
@ SYCLKernelLaunchOverloadResolution
We are performing overload resolution for a call to a function template or variable template named 's...
Definition Sema.h:13286
@ SYCLKernelLaunchLookup
We are performing name lookup for a function template or variable template named 'sycl_kernel_launch'...
Definition Sema.h:13282
Decl * Entity
The entity that is being synthesized.
Definition Sema.h:13299