1 //===- SemaSYCL.cpp - Semantic Analysis for SYCL constructs ---------------===//
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
7 //===----------------------------------------------------------------------===//
8 // This implements Semantic Analysis for SYCL constructs.
9 //===----------------------------------------------------------------------===//
11 #include "clang/Sema/SemaSYCL.h"
12 #include "clang/AST/Mangle.h"
13 #include "clang/AST/TypeOrdering.h"
14 #include "clang/Sema/Attr.h"
15 #include "clang/Sema/ParsedAttr.h"
16 #include "clang/Sema/Sema.h"
18 using namespace clang
;
20 // -----------------------------------------------------------------------------
21 // SYCL device specific diagnostics implementation
22 // -----------------------------------------------------------------------------
24 SemaSYCL::SemaSYCL(Sema
&S
) : SemaBase(S
) {}
26 Sema::SemaDiagnosticBuilder
SemaSYCL::DiagIfDeviceCode(SourceLocation Loc
,
28 assert(getLangOpts().SYCLIsDevice
&&
29 "Should only be called during SYCL compilation");
30 FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(SemaRef
.getCurLexicalContext());
31 SemaDiagnosticBuilder::Kind DiagKind
= [this, FD
] {
33 return SemaDiagnosticBuilder::K_Nop
;
34 if (SemaRef
.getEmissionStatus(FD
) == Sema::FunctionEmissionStatus::Emitted
)
35 return SemaDiagnosticBuilder::K_ImmediateWithCallStack
;
36 return SemaDiagnosticBuilder::K_Deferred
;
38 return SemaDiagnosticBuilder(DiagKind
, Loc
, DiagID
, FD
, SemaRef
);
41 static bool isZeroSizedArray(SemaSYCL
&S
, QualType Ty
) {
42 if (const auto *CAT
= S
.getASTContext().getAsConstantArrayType(Ty
))
43 return CAT
->isZeroSize();
47 void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt
,
48 llvm::DenseSet
<QualType
> Visited
,
49 ValueDecl
*DeclToCheck
) {
50 assert(getLangOpts().SYCLIsDevice
&&
51 "Should only be called during SYCL compilation");
52 // Emit notes only for the first discovered declaration of unsupported type
53 // to avoid mess of notes. This flag is to track that error already happened.
54 bool NeedToEmitNotes
= true;
56 auto Check
= [&](QualType TypeToCheck
, const ValueDecl
*D
) {
57 bool ErrorFound
= false;
58 if (isZeroSizedArray(*this, TypeToCheck
)) {
59 DiagIfDeviceCode(UsedAt
, diag::err_typecheck_zero_array_size
) << 1;
62 // Checks for other types can also be done here.
64 if (NeedToEmitNotes
) {
65 if (auto *FD
= dyn_cast
<FieldDecl
>(D
))
66 DiagIfDeviceCode(FD
->getLocation(),
67 diag::note_illegal_field_declared_here
)
68 << FD
->getType()->isPointerType() << FD
->getType();
70 DiagIfDeviceCode(D
->getLocation(), diag::note_declared_at
);
77 // In case we have a Record used do the DFS for a bad field.
78 SmallVector
<const ValueDecl
*, 4> StackForRecursion
;
79 StackForRecursion
.push_back(DeclToCheck
);
81 // While doing DFS save how we get there to emit a nice set of notes.
82 SmallVector
<const FieldDecl
*, 4> History
;
83 History
.push_back(nullptr);
86 const ValueDecl
*Next
= StackForRecursion
.pop_back_val();
88 assert(!History
.empty());
89 // Found a marker, we have gone up a level.
93 QualType NextTy
= Next
->getType();
95 if (!Visited
.insert(NextTy
).second
)
98 auto EmitHistory
= [&]() {
99 // The first element is always nullptr.
100 for (uint64_t Index
= 1; Index
< History
.size(); ++Index
) {
101 DiagIfDeviceCode(History
[Index
]->getLocation(),
102 diag::note_within_field_of_type
)
103 << History
[Index
]->getType();
107 if (Check(NextTy
, Next
)) {
110 NeedToEmitNotes
= false;
113 // In case pointer/array/reference type is met get pointee type, then
114 // proceed with that type.
115 while (NextTy
->isAnyPointerType() || NextTy
->isArrayType() ||
116 NextTy
->isReferenceType()) {
117 if (NextTy
->isArrayType())
118 NextTy
= QualType
{NextTy
->getArrayElementTypeNoTypeQual(), 0};
120 NextTy
= NextTy
->getPointeeType();
121 if (Check(NextTy
, Next
)) {
124 NeedToEmitNotes
= false;
128 if (const auto *RecDecl
= NextTy
->getAsRecordDecl()) {
129 if (auto *NextFD
= dyn_cast
<FieldDecl
>(Next
))
130 History
.push_back(NextFD
);
131 // When nullptr is discovered, this means we've gone back up a level, so
132 // the history should be cleaned.
133 StackForRecursion
.push_back(nullptr);
134 llvm::copy(RecDecl
->fields(), std::back_inserter(StackForRecursion
));
136 } while (!StackForRecursion
.empty());
139 ExprResult
SemaSYCL::BuildUniqueStableNameExpr(SourceLocation OpLoc
,
140 SourceLocation LParen
,
141 SourceLocation RParen
,
142 TypeSourceInfo
*TSI
) {
143 return SYCLUniqueStableNameExpr::Create(getASTContext(), OpLoc
, LParen
,
147 ExprResult
SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc
,
148 SourceLocation LParen
,
149 SourceLocation RParen
,
150 ParsedType ParsedTy
) {
151 TypeSourceInfo
*TSI
= nullptr;
152 QualType Ty
= SemaRef
.GetTypeFromParser(ParsedTy
, &TSI
);
157 TSI
= getASTContext().getTrivialTypeSourceInfo(Ty
, LParen
);
159 return BuildUniqueStableNameExpr(OpLoc
, LParen
, RParen
, TSI
);
162 void SemaSYCL::handleKernelAttr(Decl
*D
, const ParsedAttr
&AL
) {
163 // The 'sycl_kernel' attribute applies only to function templates.
164 const auto *FD
= cast
<FunctionDecl
>(D
);
165 const FunctionTemplateDecl
*FT
= FD
->getDescribedFunctionTemplate();
166 assert(FT
&& "Function template is expected");
168 // Function template must have at least two template parameters.
169 const TemplateParameterList
*TL
= FT
->getTemplateParameters();
170 if (TL
->size() < 2) {
171 Diag(FT
->getLocation(), diag::warn_sycl_kernel_num_of_template_params
);
175 // Template parameters must be typenames.
176 for (unsigned I
= 0; I
< 2; ++I
) {
177 const NamedDecl
*TParam
= TL
->getParam(I
);
178 if (isa
<NonTypeTemplateParmDecl
>(TParam
)) {
179 Diag(FT
->getLocation(),
180 diag::warn_sycl_kernel_invalid_template_param_type
);
185 // Function must have at least one argument.
186 if (getFunctionOrMethodNumParams(D
) != 1) {
187 Diag(FT
->getLocation(), diag::warn_sycl_kernel_num_of_function_params
);
191 // Function must return void.
192 QualType RetTy
= getFunctionOrMethodResultType(D
);
193 if (!RetTy
->isVoidType()) {
194 Diag(FT
->getLocation(), diag::warn_sycl_kernel_return_type
);
198 handleSimpleAttribute
<SYCLKernelAttr
>(*this, D
, AL
);
201 void SemaSYCL::handleKernelEntryPointAttr(Decl
*D
, const ParsedAttr
&AL
) {
202 ParsedType PT
= AL
.getTypeArg();
203 TypeSourceInfo
*TSI
= nullptr;
204 (void)SemaRef
.GetTypeFromParser(PT
, &TSI
);
205 assert(TSI
&& "no type source info for attribute argument");
206 D
->addAttr(::new (SemaRef
.Context
)
207 SYCLKernelEntryPointAttr(SemaRef
.Context
, AL
, TSI
));