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/AST/Mangle.h"
12#include "clang/Sema/Sema.h"
13#include "clang/Sema/SemaDiagnostic.h"
14
15using namespace clang;
16
17// -----------------------------------------------------------------------------
18// SYCL device specific diagnostics implementation
19// -----------------------------------------------------------------------------
20
21Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
22 unsigned DiagID) {
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] {
27 if (!FD)
28 return SemaDiagnosticBuilder::K_Nop;
29 if (getEmissionStatus(Decl: FD) == Sema::FunctionEmissionStatus::Emitted)
30 return SemaDiagnosticBuilder::K_ImmediateWithCallStack;
31 return SemaDiagnosticBuilder::K_Deferred;
32 }();
33 return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this);
34}
35
36static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
37 if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(T: Ty))
38 return CAT->getSize() == 0;
39 return false;
40}
41
42void 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;
50
51 auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
52 bool ErrorFound = false;
53 if (isZeroSizedArray(SemaRef&: *this, Ty: TypeToCheck)) {
54 SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1;
55 ErrorFound = true;
56 }
57 // Checks for other types can also be done here.
58 if (ErrorFound) {
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();
64 else
65 SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
66 }
67 }
68
69 return ErrorFound;
70 };
71
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(Elt: DeclToCheck);
75
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(Elt: nullptr);
79
80 do {
81 const ValueDecl *Next = StackForRecursion.pop_back_val();
82 if (!Next) {
83 assert(!History.empty());
84 // Found a marker, we have gone up a level.
85 History.pop_back();
86 continue;
87 }
88 QualType NextTy = Next->getType();
89
90 if (!Visited.insert(V: NextTy).second)
91 continue;
92
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();
99 }
100 };
101
102 if (Check(NextTy, Next)) {
103 if (NeedToEmitNotes)
104 EmitHistory();
105 NeedToEmitNotes = false;
106 }
107
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};
114 else
115 NextTy = NextTy->getPointeeType();
116 if (Check(NextTy, Next)) {
117 if (NeedToEmitNotes)
118 EmitHistory();
119 NeedToEmitNotes = false;
120 }
121 }
122
123 if (const auto *RecDecl = NextTy->getAsRecordDecl()) {
124 if (auto *NextFD = dyn_cast<FieldDecl>(Val: Next))
125 History.push_back(Elt: 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(Elt: nullptr);
129 llvm::copy(Range: RecDecl->fields(), Out: std::back_inserter(x&: StackForRecursion));
130 }
131 } while (!StackForRecursion.empty());
132}
133

source code of clang/lib/Sema/SemaSYCL.cpp