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