Coverage Report

Created: 2024-01-17 10:31

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