/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Sema/SemaSYCL.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
15 | | using namespace clang; |
16 | | |
17 | | // ----------------------------------------------------------------------------- |
18 | | // SYCL device specific diagnostics implementation |
19 | | // ----------------------------------------------------------------------------- |
20 | | |
21 | | Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, |
22 | 246 | unsigned DiagID) { |
23 | 246 | assert(getLangOpts().SYCLIsDevice && |
24 | 246 | "Should only be called during SYCL compilation"); |
25 | 0 | FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext()); |
26 | 246 | SemaDiagnosticBuilder::Kind DiagKind = [this, FD] { |
27 | 246 | if (!FD) |
28 | 22 | return SemaDiagnosticBuilder::K_Nop; |
29 | 224 | if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) |
30 | 37 | return SemaDiagnosticBuilder::K_ImmediateWithCallStack; |
31 | 187 | return SemaDiagnosticBuilder::K_Deferred; |
32 | 224 | }(); |
33 | 246 | return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this); |
34 | 246 | } |
35 | | |
36 | 1.12k | bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { |
37 | 1.12k | assert(getLangOpts().SYCLIsDevice && |
38 | 1.12k | "Should only be called during SYCL compilation"); |
39 | 0 | assert(Callee && "Callee may not be null."); |
40 | | |
41 | | // Errors in an unevaluated context don't need to be generated, |
42 | | // so we can safely skip them. |
43 | 1.12k | if (isUnevaluatedContext() || isConstantEvaluated()1.12k ) |
44 | 4 | return true; |
45 | | |
46 | 1.12k | SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop; |
47 | | |
48 | 1.12k | return DiagKind != SemaDiagnosticBuilder::K_Immediate && |
49 | 1.12k | DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; |
50 | 1.12k | } |
51 | | |
52 | 1.69k | static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { |
53 | 1.69k | if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) |
54 | 112 | return CAT->getSize() == 0; |
55 | 1.58k | return false; |
56 | 1.69k | } |
57 | | |
58 | | void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, |
59 | | llvm::DenseSet<QualType> Visited, |
60 | 1.22k | ValueDecl *DeclToCheck) { |
61 | 1.22k | assert(getLangOpts().SYCLIsDevice && |
62 | 1.22k | "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 | 0 | bool NeedToEmitNotes = true; |
66 | | |
67 | 1.69k | auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { |
68 | 1.69k | bool ErrorFound = false; |
69 | 1.69k | if (isZeroSizedArray(*this, TypeToCheck)) { |
70 | 61 | SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; |
71 | 61 | ErrorFound = true; |
72 | 61 | } |
73 | | // Checks for other types can also be done here. |
74 | 1.69k | if (ErrorFound) { |
75 | 61 | if (NeedToEmitNotes) { |
76 | 39 | if (auto *FD = dyn_cast<FieldDecl>(D)) |
77 | 31 | SYCLDiagIfDeviceCode(FD->getLocation(), |
78 | 31 | diag::note_illegal_field_declared_here) |
79 | 31 | << FD->getType()->isPointerType() << FD->getType(); |
80 | 8 | else |
81 | 8 | SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at); |
82 | 39 | } |
83 | 61 | } |
84 | | |
85 | 1.69k | return ErrorFound; |
86 | 1.69k | }; |
87 | | |
88 | | // In case we have a Record used do the DFS for a bad field. |
89 | 1.22k | SmallVector<const ValueDecl *, 4> StackForRecursion; |
90 | 1.22k | StackForRecursion.push_back(DeclToCheck); |
91 | | |
92 | | // While doing DFS save how we get there to emit a nice set of notes. |
93 | 1.22k | SmallVector<const FieldDecl *, 4> History; |
94 | 1.22k | History.push_back(nullptr); |
95 | | |
96 | 1.61k | do { |
97 | 1.61k | const ValueDecl *Next = StackForRecursion.pop_back_val(); |
98 | 1.61k | if (!Next) { |
99 | 189 | assert(!History.empty()); |
100 | | // Found a marker, we have gone up a level. |
101 | 0 | History.pop_back(); |
102 | 189 | continue; |
103 | 189 | } |
104 | 1.42k | QualType NextTy = Next->getType(); |
105 | | |
106 | 1.42k | if (!Visited.insert(NextTy).second) |
107 | 3 | continue; |
108 | | |
109 | 1.42k | auto EmitHistory = [&]() { |
110 | | // The first element is always nullptr. |
111 | 63 | for (uint64_t Index = 1; Index < History.size(); ++Index24 ) { |
112 | 24 | SYCLDiagIfDeviceCode(History[Index]->getLocation(), |
113 | 24 | diag::note_within_field_of_type) |
114 | 24 | << History[Index]->getType(); |
115 | 24 | } |
116 | 39 | }; |
117 | | |
118 | 1.42k | if (Check(NextTy, Next)) { |
119 | 50 | if (NeedToEmitNotes) |
120 | 28 | EmitHistory(); |
121 | 50 | NeedToEmitNotes = false; |
122 | 50 | } |
123 | | |
124 | | // In case pointer/array/reference type is met get pointee type, then |
125 | | // proceed with that type. |
126 | 1.69k | while (NextTy->isAnyPointerType() || NextTy->isArrayType()1.56k || |
127 | 1.69k | NextTy->isReferenceType()1.45k ) { |
128 | 279 | if (NextTy->isArrayType()) |
129 | 112 | NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0}; |
130 | 167 | else |
131 | 167 | NextTy = NextTy->getPointeeType(); |
132 | 279 | if (Check(NextTy, Next)) { |
133 | 11 | if (NeedToEmitNotes) |
134 | 11 | EmitHistory(); |
135 | 11 | NeedToEmitNotes = false; |
136 | 11 | } |
137 | 279 | } |
138 | | |
139 | 1.42k | if (const auto *RecDecl = NextTy->getAsRecordDecl()) { |
140 | 189 | if (auto *NextFD = dyn_cast<FieldDecl>(Next)) |
141 | 53 | 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 | 189 | StackForRecursion.push_back(nullptr); |
145 | 189 | llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion)); |
146 | 189 | } |
147 | 1.61k | } while (!StackForRecursion.empty()); |
148 | 1.22k | } |