xref: /freebsd/contrib/llvm-project/clang/lib/Sema/SemaSYCL.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
15ffd83dbSDimitry Andric //===- SemaSYCL.cpp - Semantic Analysis for SYCL constructs ---------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric // This implements Semantic Analysis for SYCL constructs.
95ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
105ffd83dbSDimitry Andric 
11fe6060f1SDimitry Andric #include "clang/AST/Mangle.h"
125ffd83dbSDimitry Andric #include "clang/Sema/Sema.h"
135ffd83dbSDimitry Andric #include "clang/Sema/SemaDiagnostic.h"
145ffd83dbSDimitry Andric 
155ffd83dbSDimitry Andric using namespace clang;
165ffd83dbSDimitry Andric 
175ffd83dbSDimitry Andric // -----------------------------------------------------------------------------
185ffd83dbSDimitry Andric // SYCL device specific diagnostics implementation
195ffd83dbSDimitry Andric // -----------------------------------------------------------------------------
205ffd83dbSDimitry Andric 
21e8d8bef9SDimitry Andric Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
225ffd83dbSDimitry Andric                                                        unsigned DiagID) {
235ffd83dbSDimitry Andric   assert(getLangOpts().SYCLIsDevice &&
245ffd83dbSDimitry Andric          "Should only be called during SYCL compilation");
255ffd83dbSDimitry Andric   FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
26e8d8bef9SDimitry Andric   SemaDiagnosticBuilder::Kind DiagKind = [this, FD] {
275ffd83dbSDimitry Andric     if (!FD)
28e8d8bef9SDimitry Andric       return SemaDiagnosticBuilder::K_Nop;
295ffd83dbSDimitry Andric     if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted)
30e8d8bef9SDimitry Andric       return SemaDiagnosticBuilder::K_ImmediateWithCallStack;
31e8d8bef9SDimitry Andric     return SemaDiagnosticBuilder::K_Deferred;
325ffd83dbSDimitry Andric   }();
33e8d8bef9SDimitry Andric   return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this);
345ffd83dbSDimitry Andric }
355ffd83dbSDimitry Andric 
365ffd83dbSDimitry Andric bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
375ffd83dbSDimitry Andric   assert(getLangOpts().SYCLIsDevice &&
385ffd83dbSDimitry Andric          "Should only be called during SYCL compilation");
395ffd83dbSDimitry Andric   assert(Callee && "Callee may not be null.");
405ffd83dbSDimitry Andric 
41349cc55cSDimitry Andric   // Errors in an unevaluated context don't need to be generated,
425ffd83dbSDimitry Andric   // so we can safely skip them.
435ffd83dbSDimitry Andric   if (isUnevaluatedContext() || isConstantEvaluated())
445ffd83dbSDimitry Andric     return true;
455ffd83dbSDimitry Andric 
46e8d8bef9SDimitry Andric   SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop;
475ffd83dbSDimitry Andric 
48e8d8bef9SDimitry Andric   return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
49e8d8bef9SDimitry Andric          DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack;
505ffd83dbSDimitry Andric }
51*04eeddc0SDimitry Andric 
52*04eeddc0SDimitry Andric static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
53*04eeddc0SDimitry Andric   if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty))
54*04eeddc0SDimitry Andric     return CAT->getSize() == 0;
55*04eeddc0SDimitry Andric   return false;
56*04eeddc0SDimitry Andric }
57*04eeddc0SDimitry Andric 
58*04eeddc0SDimitry Andric void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
59*04eeddc0SDimitry Andric                                       llvm::DenseSet<QualType> Visited,
60*04eeddc0SDimitry Andric                                       ValueDecl *DeclToCheck) {
61*04eeddc0SDimitry Andric   assert(getLangOpts().SYCLIsDevice &&
62*04eeddc0SDimitry Andric          "Should only be called during SYCL compilation");
63*04eeddc0SDimitry Andric   // Emit notes only for the first discovered declaration of unsupported type
64*04eeddc0SDimitry Andric   // to avoid mess of notes. This flag is to track that error already happened.
65*04eeddc0SDimitry Andric   bool NeedToEmitNotes = true;
66*04eeddc0SDimitry Andric 
67*04eeddc0SDimitry Andric   auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
68*04eeddc0SDimitry Andric     bool ErrorFound = false;
69*04eeddc0SDimitry Andric     if (isZeroSizedArray(*this, TypeToCheck)) {
70*04eeddc0SDimitry Andric       SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1;
71*04eeddc0SDimitry Andric       ErrorFound = true;
72*04eeddc0SDimitry Andric     }
73*04eeddc0SDimitry Andric     // Checks for other types can also be done here.
74*04eeddc0SDimitry Andric     if (ErrorFound) {
75*04eeddc0SDimitry Andric       if (NeedToEmitNotes) {
76*04eeddc0SDimitry Andric         if (auto *FD = dyn_cast<FieldDecl>(D))
77*04eeddc0SDimitry Andric           SYCLDiagIfDeviceCode(FD->getLocation(),
78*04eeddc0SDimitry Andric                                diag::note_illegal_field_declared_here)
79*04eeddc0SDimitry Andric               << FD->getType()->isPointerType() << FD->getType();
80*04eeddc0SDimitry Andric         else
81*04eeddc0SDimitry Andric           SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
82*04eeddc0SDimitry Andric       }
83*04eeddc0SDimitry Andric     }
84*04eeddc0SDimitry Andric 
85*04eeddc0SDimitry Andric     return ErrorFound;
86*04eeddc0SDimitry Andric   };
87*04eeddc0SDimitry Andric 
88*04eeddc0SDimitry Andric   // In case we have a Record used do the DFS for a bad field.
89*04eeddc0SDimitry Andric   SmallVector<const ValueDecl *, 4> StackForRecursion;
90*04eeddc0SDimitry Andric   StackForRecursion.push_back(DeclToCheck);
91*04eeddc0SDimitry Andric 
92*04eeddc0SDimitry Andric   // While doing DFS save how we get there to emit a nice set of notes.
93*04eeddc0SDimitry Andric   SmallVector<const FieldDecl *, 4> History;
94*04eeddc0SDimitry Andric   History.push_back(nullptr);
95*04eeddc0SDimitry Andric 
96*04eeddc0SDimitry Andric   do {
97*04eeddc0SDimitry Andric     const ValueDecl *Next = StackForRecursion.pop_back_val();
98*04eeddc0SDimitry Andric     if (!Next) {
99*04eeddc0SDimitry Andric       assert(!History.empty());
100*04eeddc0SDimitry Andric       // Found a marker, we have gone up a level.
101*04eeddc0SDimitry Andric       History.pop_back();
102*04eeddc0SDimitry Andric       continue;
103*04eeddc0SDimitry Andric     }
104*04eeddc0SDimitry Andric     QualType NextTy = Next->getType();
105*04eeddc0SDimitry Andric 
106*04eeddc0SDimitry Andric     if (!Visited.insert(NextTy).second)
107*04eeddc0SDimitry Andric       continue;
108*04eeddc0SDimitry Andric 
109*04eeddc0SDimitry Andric     auto EmitHistory = [&]() {
110*04eeddc0SDimitry Andric       // The first element is always nullptr.
111*04eeddc0SDimitry Andric       for (uint64_t Index = 1; Index < History.size(); ++Index) {
112*04eeddc0SDimitry Andric         SYCLDiagIfDeviceCode(History[Index]->getLocation(),
113*04eeddc0SDimitry Andric                              diag::note_within_field_of_type)
114*04eeddc0SDimitry Andric             << History[Index]->getType();
115*04eeddc0SDimitry Andric       }
116*04eeddc0SDimitry Andric     };
117*04eeddc0SDimitry Andric 
118*04eeddc0SDimitry Andric     if (Check(NextTy, Next)) {
119*04eeddc0SDimitry Andric       if (NeedToEmitNotes)
120*04eeddc0SDimitry Andric         EmitHistory();
121*04eeddc0SDimitry Andric       NeedToEmitNotes = false;
122*04eeddc0SDimitry Andric     }
123*04eeddc0SDimitry Andric 
124*04eeddc0SDimitry Andric     // In case pointer/array/reference type is met get pointee type, then
125*04eeddc0SDimitry Andric     // proceed with that type.
126*04eeddc0SDimitry Andric     while (NextTy->isAnyPointerType() || NextTy->isArrayType() ||
127*04eeddc0SDimitry Andric            NextTy->isReferenceType()) {
128*04eeddc0SDimitry Andric       if (NextTy->isArrayType())
129*04eeddc0SDimitry Andric         NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0};
130*04eeddc0SDimitry Andric       else
131*04eeddc0SDimitry Andric         NextTy = NextTy->getPointeeType();
132*04eeddc0SDimitry Andric       if (Check(NextTy, Next)) {
133*04eeddc0SDimitry Andric         if (NeedToEmitNotes)
134*04eeddc0SDimitry Andric           EmitHistory();
135*04eeddc0SDimitry Andric         NeedToEmitNotes = false;
136*04eeddc0SDimitry Andric       }
137*04eeddc0SDimitry Andric     }
138*04eeddc0SDimitry Andric 
139*04eeddc0SDimitry Andric     if (const auto *RecDecl = NextTy->getAsRecordDecl()) {
140*04eeddc0SDimitry Andric       if (auto *NextFD = dyn_cast<FieldDecl>(Next))
141*04eeddc0SDimitry Andric         History.push_back(NextFD);
142*04eeddc0SDimitry Andric       // When nullptr is discovered, this means we've gone back up a level, so
143*04eeddc0SDimitry Andric       // the history should be cleaned.
144*04eeddc0SDimitry Andric       StackForRecursion.push_back(nullptr);
145*04eeddc0SDimitry Andric       llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion));
146*04eeddc0SDimitry Andric     }
147*04eeddc0SDimitry Andric   } while (!StackForRecursion.empty());
148*04eeddc0SDimitry Andric }
149