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/AST/Mangle.h"
12 #include "clang/Sema/Sema.h"
13 #include "clang/Sema/SemaDiagnostic.h"
15 using namespace clang
;
17 // -----------------------------------------------------------------------------
18 // SYCL device specific diagnostics implementation
19 // -----------------------------------------------------------------------------
21 Sema::SemaDiagnosticBuilder
Sema::SYCLDiagIfDeviceCode(SourceLocation Loc
,
23 assert(getLangOpts().SYCLIsDevice
&&
24 "Should only be called during SYCL compilation");
25 FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(getCurLexicalContext());
26 SemaDiagnosticBuilder::Kind DiagKind
= [this, FD
] {
28 return SemaDiagnosticBuilder::K_Nop
;
29 if (getEmissionStatus(FD
) == Sema::FunctionEmissionStatus::Emitted
)
30 return SemaDiagnosticBuilder::K_ImmediateWithCallStack
;
31 return SemaDiagnosticBuilder::K_Deferred
;
33 return SemaDiagnosticBuilder(DiagKind
, Loc
, DiagID
, FD
, *this);
36 bool Sema::checkSYCLDeviceFunction(SourceLocation Loc
, FunctionDecl
*Callee
) {
37 assert(getLangOpts().SYCLIsDevice
&&
38 "Should only be called during SYCL compilation");
39 assert(Callee
&& "Callee may not be null.");
41 // Errors in an unevaluated context don't need to be generated,
42 // so we can safely skip them.
43 if (isUnevaluatedContext() || isConstantEvaluated())
46 SemaDiagnosticBuilder::Kind DiagKind
= SemaDiagnosticBuilder::K_Nop
;
48 return DiagKind
!= SemaDiagnosticBuilder::K_Immediate
&&
49 DiagKind
!= SemaDiagnosticBuilder::K_ImmediateWithCallStack
;
52 static bool isZeroSizedArray(Sema
&SemaRef
, QualType Ty
) {
53 if (const auto *CAT
= SemaRef
.getASTContext().getAsConstantArrayType(Ty
))
54 return CAT
->getSize() == 0;
58 void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt
,
59 llvm::DenseSet
<QualType
> Visited
,
60 ValueDecl
*DeclToCheck
) {
61 assert(getLangOpts().SYCLIsDevice
&&
62 "Should only be called during SYCL compilation");
63 // Emit notes only for the first discovered declaration of unsupported type
64 // to avoid mess of notes. This flag is to track that error already happened.
65 bool NeedToEmitNotes
= true;
67 auto Check
= [&](QualType TypeToCheck
, const ValueDecl
*D
) {
68 bool ErrorFound
= false;
69 if (isZeroSizedArray(*this, TypeToCheck
)) {
70 SYCLDiagIfDeviceCode(UsedAt
, diag::err_typecheck_zero_array_size
) << 1;
73 // Checks for other types can also be done here.
75 if (NeedToEmitNotes
) {
76 if (auto *FD
= dyn_cast
<FieldDecl
>(D
))
77 SYCLDiagIfDeviceCode(FD
->getLocation(),
78 diag::note_illegal_field_declared_here
)
79 << FD
->getType()->isPointerType() << FD
->getType();
81 SYCLDiagIfDeviceCode(D
->getLocation(), diag::note_declared_at
);
88 // In case we have a Record used do the DFS for a bad field.
89 SmallVector
<const ValueDecl
*, 4> StackForRecursion
;
90 StackForRecursion
.push_back(DeclToCheck
);
92 // While doing DFS save how we get there to emit a nice set of notes.
93 SmallVector
<const FieldDecl
*, 4> History
;
94 History
.push_back(nullptr);
97 const ValueDecl
*Next
= StackForRecursion
.pop_back_val();
99 assert(!History
.empty());
100 // Found a marker, we have gone up a level.
104 QualType NextTy
= Next
->getType();
106 if (!Visited
.insert(NextTy
).second
)
109 auto EmitHistory
= [&]() {
110 // The first element is always nullptr.
111 for (uint64_t Index
= 1; Index
< History
.size(); ++Index
) {
112 SYCLDiagIfDeviceCode(History
[Index
]->getLocation(),
113 diag::note_within_field_of_type
)
114 << History
[Index
]->getType();
118 if (Check(NextTy
, Next
)) {
121 NeedToEmitNotes
= false;
124 // In case pointer/array/reference type is met get pointee type, then
125 // proceed with that type.
126 while (NextTy
->isAnyPointerType() || NextTy
->isArrayType() ||
127 NextTy
->isReferenceType()) {
128 if (NextTy
->isArrayType())
129 NextTy
= QualType
{NextTy
->getArrayElementTypeNoTypeQual(), 0};
131 NextTy
= NextTy
->getPointeeType();
132 if (Check(NextTy
, Next
)) {
135 NeedToEmitNotes
= false;
139 if (const auto *RecDecl
= NextTy
->getAsRecordDecl()) {
140 if (auto *NextFD
= dyn_cast
<FieldDecl
>(Next
))
141 History
.push_back(NextFD
);
142 // When nullptr is discovered, this means we've gone back up a level, so
143 // the history should be cleaned.
144 StackForRecursion
.push_back(nullptr);
145 llvm::copy(RecDecl
->fields(), std::back_inserter(StackForRecursion
));
147 } while (!StackForRecursion
.empty());