//===- SemaSYCL.cpp - Semantic Analysis for SYCL constructs ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // This implements Semantic Analysis for SYCL constructs. //===----------------------------------------------------------------------===// #include "clang/Sema/SemaSYCL.h" #include "clang/AST/Mangle.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" using namespace clang; // ----------------------------------------------------------------------------- // SYCL device specific diagnostics implementation // ----------------------------------------------------------------------------- SemaSYCL::SemaSYCL(Sema &S) : SemaBase(S) {} Sema::SemaDiagnosticBuilder SemaSYCL::DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(getLangOpts().SYCLIsDevice && "Should only be called during SYCL compilation"); FunctionDecl *FD = dyn_cast(SemaRef.getCurLexicalContext()); SemaDiagnosticBuilder::Kind DiagKind = [this, FD] { if (!FD) return SemaDiagnosticBuilder::K_Nop; if (SemaRef.getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) return SemaDiagnosticBuilder::K_ImmediateWithCallStack; return SemaDiagnosticBuilder::K_Deferred; }(); return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, SemaRef); } static bool isZeroSizedArray(SemaSYCL &S, QualType Ty) { if (const auto *CAT = S.getASTContext().getAsConstantArrayType(Ty)) return CAT->isZeroSize(); return false; } void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt, llvm::DenseSet Visited, ValueDecl *DeclToCheck) { assert(getLangOpts().SYCLIsDevice && "Should only be called during SYCL compilation"); // Emit notes only for the first discovered declaration of unsupported type // to avoid mess of notes. This flag is to track that error already happened. bool NeedToEmitNotes = true; auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { bool ErrorFound = false; if (isZeroSizedArray(*this, TypeToCheck)) { DiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; ErrorFound = true; } // Checks for other types can also be done here. if (ErrorFound) { if (NeedToEmitNotes) { if (auto *FD = dyn_cast(D)) DiagIfDeviceCode(FD->getLocation(), diag::note_illegal_field_declared_here) << FD->getType()->isPointerType() << FD->getType(); else DiagIfDeviceCode(D->getLocation(), diag::note_declared_at); } } return ErrorFound; }; // In case we have a Record used do the DFS for a bad field. SmallVector StackForRecursion; StackForRecursion.push_back(DeclToCheck); // While doing DFS save how we get there to emit a nice set of notes. SmallVector History; History.push_back(nullptr); do { const ValueDecl *Next = StackForRecursion.pop_back_val(); if (!Next) { assert(!History.empty()); // Found a marker, we have gone up a level. History.pop_back(); continue; } QualType NextTy = Next->getType(); if (!Visited.insert(NextTy).second) continue; auto EmitHistory = [&]() { // The first element is always nullptr. for (uint64_t Index = 1; Index < History.size(); ++Index) { DiagIfDeviceCode(History[Index]->getLocation(), diag::note_within_field_of_type) << History[Index]->getType(); } }; if (Check(NextTy, Next)) { if (NeedToEmitNotes) EmitHistory(); NeedToEmitNotes = false; } // In case pointer/array/reference type is met get pointee type, then // proceed with that type. while (NextTy->isAnyPointerType() || NextTy->isArrayType() || NextTy->isReferenceType()) { if (NextTy->isArrayType()) NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0}; else NextTy = NextTy->getPointeeType(); if (Check(NextTy, Next)) { if (NeedToEmitNotes) EmitHistory(); NeedToEmitNotes = false; } } if (const auto *RecDecl = NextTy->getAsRecordDecl()) { if (auto *NextFD = dyn_cast(Next)) History.push_back(NextFD); // When nullptr is discovered, this means we've gone back up a level, so // the history should be cleaned. StackForRecursion.push_back(nullptr); llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion)); } } while (!StackForRecursion.empty()); } ExprResult SemaSYCL::BuildUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, TypeSourceInfo *TSI) { return SYCLUniqueStableNameExpr::Create(getASTContext(), OpLoc, LParen, RParen, TSI); } ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, SourceLocation RParen, ParsedType ParsedTy) { TypeSourceInfo *TSI = nullptr; QualType Ty = SemaRef.GetTypeFromParser(ParsedTy, &TSI); if (Ty.isNull()) return ExprError(); if (!TSI) TSI = getASTContext().getTrivialTypeSourceInfo(Ty, LParen); return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); }