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 static bool isZeroSizedArray(Sema
&SemaRef
, QualType Ty
) {
37 if (const auto *CAT
= SemaRef
.getASTContext().getAsConstantArrayType(Ty
))
38 return CAT
->getSize() == 0;
42 void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt
,
43 llvm::DenseSet
<QualType
> Visited
,
44 ValueDecl
*DeclToCheck
) {
45 assert(getLangOpts().SYCLIsDevice
&&
46 "Should only be called during SYCL compilation");
47 // Emit notes only for the first discovered declaration of unsupported type
48 // to avoid mess of notes. This flag is to track that error already happened.
49 bool NeedToEmitNotes
= true;
51 auto Check
= [&](QualType TypeToCheck
, const ValueDecl
*D
) {
52 bool ErrorFound
= false;
53 if (isZeroSizedArray(*this, TypeToCheck
)) {
54 SYCLDiagIfDeviceCode(UsedAt
, diag::err_typecheck_zero_array_size
) << 1;
57 // Checks for other types can also be done here.
59 if (NeedToEmitNotes
) {
60 if (auto *FD
= dyn_cast
<FieldDecl
>(D
))
61 SYCLDiagIfDeviceCode(FD
->getLocation(),
62 diag::note_illegal_field_declared_here
)
63 << FD
->getType()->isPointerType() << FD
->getType();
65 SYCLDiagIfDeviceCode(D
->getLocation(), diag::note_declared_at
);
72 // In case we have a Record used do the DFS for a bad field.
73 SmallVector
<const ValueDecl
*, 4> StackForRecursion
;
74 StackForRecursion
.push_back(DeclToCheck
);
76 // While doing DFS save how we get there to emit a nice set of notes.
77 SmallVector
<const FieldDecl
*, 4> History
;
78 History
.push_back(nullptr);
81 const ValueDecl
*Next
= StackForRecursion
.pop_back_val();
83 assert(!History
.empty());
84 // Found a marker, we have gone up a level.
88 QualType NextTy
= Next
->getType();
90 if (!Visited
.insert(NextTy
).second
)
93 auto EmitHistory
= [&]() {
94 // The first element is always nullptr.
95 for (uint64_t Index
= 1; Index
< History
.size(); ++Index
) {
96 SYCLDiagIfDeviceCode(History
[Index
]->getLocation(),
97 diag::note_within_field_of_type
)
98 << History
[Index
]->getType();
102 if (Check(NextTy
, Next
)) {
105 NeedToEmitNotes
= false;
108 // In case pointer/array/reference type is met get pointee type, then
109 // proceed with that type.
110 while (NextTy
->isAnyPointerType() || NextTy
->isArrayType() ||
111 NextTy
->isReferenceType()) {
112 if (NextTy
->isArrayType())
113 NextTy
= QualType
{NextTy
->getArrayElementTypeNoTypeQual(), 0};
115 NextTy
= NextTy
->getPointeeType();
116 if (Check(NextTy
, Next
)) {
119 NeedToEmitNotes
= false;
123 if (const auto *RecDecl
= NextTy
->getAsRecordDecl()) {
124 if (auto *NextFD
= dyn_cast
<FieldDecl
>(Next
))
125 History
.push_back(NextFD
);
126 // When nullptr is discovered, this means we've gone back up a level, so
127 // the history should be cleaned.
128 StackForRecursion
.push_back(nullptr);
129 llvm::copy(RecDecl
->fields(), std::back_inserter(StackForRecursion
));
131 } while (!StackForRecursion
.empty());