123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- //===- 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/AST/Mangle.h"
- #include "clang/Sema/Sema.h"
- #include "clang/Sema/SemaDiagnostic.h"
- using namespace clang;
- // -----------------------------------------------------------------------------
- // SYCL device specific diagnostics implementation
- // -----------------------------------------------------------------------------
- Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
- unsigned DiagID) {
- assert(getLangOpts().SYCLIsDevice &&
- "Should only be called during SYCL compilation");
- FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
- SemaDiagnosticBuilder::Kind DiagKind = [this, FD] {
- if (!FD)
- return SemaDiagnosticBuilder::K_Nop;
- if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted)
- return SemaDiagnosticBuilder::K_ImmediateWithCallStack;
- return SemaDiagnosticBuilder::K_Deferred;
- }();
- return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this);
- }
- bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
- assert(getLangOpts().SYCLIsDevice &&
- "Should only be called during SYCL compilation");
- assert(Callee && "Callee may not be null.");
- // Errors in an unevaluated context don't need to be generated,
- // so we can safely skip them.
- if (isUnevaluatedContext() || isConstantEvaluated())
- return true;
- SemaDiagnosticBuilder::Kind DiagKind = SemaDiagnosticBuilder::K_Nop;
- return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
- DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack;
- }
- static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
- if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty))
- return CAT->getSize() == 0;
- return false;
- }
- void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
- llvm::DenseSet<QualType> 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)) {
- SYCLDiagIfDeviceCode(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<FieldDecl>(D))
- SYCLDiagIfDeviceCode(FD->getLocation(),
- diag::note_illegal_field_declared_here)
- << FD->getType()->isPointerType() << FD->getType();
- else
- SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
- }
- }
- return ErrorFound;
- };
- // In case we have a Record used do the DFS for a bad field.
- SmallVector<const ValueDecl *, 4> StackForRecursion;
- StackForRecursion.push_back(DeclToCheck);
- // While doing DFS save how we get there to emit a nice set of notes.
- SmallVector<const FieldDecl *, 4> 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) {
- SYCLDiagIfDeviceCode(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<FieldDecl>(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());
- }
|