xref: /freebsd/contrib/llvm-project/clang/lib/Sema/SemaSYCL.cpp (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
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                                                        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(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 
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.");
40 
41   // Errors in an unevaluated context don't need to be generated,
42   // so we can safely skip them.
43   if (isUnevaluatedContext() || isConstantEvaluated())
44     return true;
45 
46   SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop;
47 
48   return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
49          DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack;
50 }
51 
52 static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
53   if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty))
54     return CAT->getSize() == 0;
55   return false;
56 }
57 
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;
66 
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;
71       ErrorFound = true;
72     }
73     // Checks for other types can also be done here.
74     if (ErrorFound) {
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();
80         else
81           SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
82       }
83     }
84 
85     return ErrorFound;
86   };
87 
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);
91 
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);
95 
96   do {
97     const ValueDecl *Next = StackForRecursion.pop_back_val();
98     if (!Next) {
99       assert(!History.empty());
100       // Found a marker, we have gone up a level.
101       History.pop_back();
102       continue;
103     }
104     QualType NextTy = Next->getType();
105 
106     if (!Visited.insert(NextTy).second)
107       continue;
108 
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();
115       }
116     };
117 
118     if (Check(NextTy, Next)) {
119       if (NeedToEmitNotes)
120         EmitHistory();
121       NeedToEmitNotes = false;
122     }
123 
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};
130       else
131         NextTy = NextTy->getPointeeType();
132       if (Check(NextTy, Next)) {
133         if (NeedToEmitNotes)
134           EmitHistory();
135         NeedToEmitNotes = false;
136       }
137     }
138 
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));
146     }
147   } while (!StackForRecursion.empty());
148 }
149