Coverage Report

Created: 2022-07-16 07:03

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