clang  16.0.0git
SemaSYCL.cpp
Go to the documentation of this file.
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"
14 
15 using namespace clang;
16 
17 // -----------------------------------------------------------------------------
18 // SYCL device specific diagnostics implementation
19 // -----------------------------------------------------------------------------
20 
22  unsigned DiagID) {
23  assert(getLangOpts().SYCLIsDevice &&
24  "Should only be called during SYCL compilation");
25  FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
26  SemaDiagnosticBuilder::Kind DiagKind = [this, FD] {
27  if (!FD)
32  }();
33  return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this);
34 }
35 
37  assert(getLangOpts().SYCLIsDevice &&
38  "Should only be called during SYCL compilation");
39  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.
44  return true;
45 
47 
48  return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
50 }
51 
52 static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
53  if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty))
54  return CAT->getSize() == 0;
55  return false;
56 }
57 
60  ValueDecl *DeclToCheck) {
61  assert(getLangOpts().SYCLIsDevice &&
62  "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  bool NeedToEmitNotes = true;
66 
67  auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
68  bool ErrorFound = false;
69  if (isZeroSizedArray(*this, TypeToCheck)) {
70  SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1;
71  ErrorFound = true;
72  }
73  // Checks for other types can also be done here.
74  if (ErrorFound) {
75  if (NeedToEmitNotes) {
76  if (auto *FD = dyn_cast<FieldDecl>(D))
77  SYCLDiagIfDeviceCode(FD->getLocation(),
78  diag::note_illegal_field_declared_here)
79  << FD->getType()->isPointerType() << FD->getType();
80  else
81  SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
82  }
83  }
84 
85  return ErrorFound;
86  };
87 
88  // In case we have a Record used do the DFS for a bad field.
89  SmallVector<const ValueDecl *, 4> StackForRecursion;
90  StackForRecursion.push_back(DeclToCheck);
91 
92  // While doing DFS save how we get there to emit a nice set of notes.
94  History.push_back(nullptr);
95 
96  do {
97  const ValueDecl *Next = StackForRecursion.pop_back_val();
98  if (!Next) {
99  assert(!History.empty());
100  // Found a marker, we have gone up a level.
101  History.pop_back();
102  continue;
103  }
104  QualType NextTy = Next->getType();
105 
106  if (!Visited.insert(NextTy).second)
107  continue;
108 
109  auto EmitHistory = [&]() {
110  // The first element is always nullptr.
111  for (uint64_t Index = 1; Index < History.size(); ++Index) {
112  SYCLDiagIfDeviceCode(History[Index]->getLocation(),
113  diag::note_within_field_of_type)
114  << History[Index]->getType();
115  }
116  };
117 
118  if (Check(NextTy, Next)) {
119  if (NeedToEmitNotes)
120  EmitHistory();
121  NeedToEmitNotes = false;
122  }
123 
124  // In case pointer/array/reference type is met get pointee type, then
125  // proceed with that type.
126  while (NextTy->isAnyPointerType() || NextTy->isArrayType() ||
127  NextTy->isReferenceType()) {
128  if (NextTy->isArrayType())
129  NextTy = QualType{NextTy->getArrayElementTypeNoTypeQual(), 0};
130  else
131  NextTy = NextTy->getPointeeType();
132  if (Check(NextTy, Next)) {
133  if (NeedToEmitNotes)
134  EmitHistory();
135  NeedToEmitNotes = false;
136  }
137  }
138 
139  if (const auto *RecDecl = NextTy->getAsRecordDecl()) {
140  if (auto *NextFD = dyn_cast<FieldDecl>(Next))
141  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  StackForRecursion.push_back(nullptr);
145  llvm::copy(RecDecl->fields(), std::back_inserter(StackForRecursion));
146  }
147  } while (!StackForRecursion.empty());
148 }
clang::Sema::getASTContext
ASTContext & getASTContext() const
Definition: Sema.h:1637
clang::Sema::SemaDiagnosticBuilder::Kind
Kind
Definition: Sema.h:1747
clang::Type::getArrayElementTypeNoTypeQual
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition: Type.cpp:369
llvm::SmallVector< const ValueDecl *, 4 >
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:86
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:737
isZeroSizedArray
static bool isZeroSizedArray(Sema &SemaRef, QualType Ty)
Definition: SemaSYCL.cpp:52
clang::Sema::isUnevaluatedContext
bool isUnevaluatedContext() const
Determines whether we are currently in a context that is not evaluated as per C++ [expr] p5.
Definition: Sema.h:9617
clang::Sema::getLangOpts
const LangOptions & getLangOpts() const
Definition: Sema.h:1630
clang::Sema::getCurLexicalContext
DeclContext * getCurLexicalContext() const
Definition: Sema.h:13645
clang::Type::isReferenceType
bool isReferenceType() const
Definition: Type.h:6895
clang::ASTContext::getAsConstantArrayType
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2699
hlsl::uint64_t
unsigned long uint64_t
Definition: hlsl_basic_types.h:25
clang::Sema::SemaDiagnosticBuilder::K_Nop
@ K_Nop
Emit no diagnostics.
Definition: Sema.h:1749
clang::Sema::SemaDiagnosticBuilder::K_Immediate
@ K_Immediate
Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
Definition: Sema.h:1751
clang::Type::getPointeeType
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:625
clang::Sema::deepTypeCheckForSYCLDevice
void deepTypeCheckForSYCLDevice(SourceLocation UsedAt, llvm::DenseSet< QualType > Visited, ValueDecl *DeclToCheck)
Definition: SemaSYCL.cpp:58
llvm::DenseSet
Definition: Sema.h:77
Sema.h
clang::Sema::SemaDiagnosticBuilder::K_Deferred
@ K_Deferred
Create a deferred diagnostic, which is emitted only if the function it's attached to is codegen'ed.
Definition: Sema.h:1759
clang::Sema::SYCLDiagIfDeviceCode
SemaDiagnosticBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID)
Creates a SemaDiagnosticBuilder that emits the diagnostic if the current context is "used as device c...
Definition: SemaSYCL.cpp:21
SemaDiagnostic.h
clang::ValueDecl
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:701
clang::Sema::SemaDiagnosticBuilder::K_ImmediateWithCallStack
@ K_ImmediateWithCallStack
Emit the diagnostic immediately, and, if it's a warning or error, also emit a call stack showing how ...
Definition: Sema.h:1755
clang::Sema
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:358
clang::Type::getAsRecordDecl
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1764
clang::Sema::isConstantEvaluated
bool isConstantEvaluated()
Definition: Sema.h:1044
clang::Sema::SemaDiagnosticBuilder
A generic diagnostic builder for errors which may or may not be deferred.
Definition: Sema.h:1745
clang::Sema::getEmissionStatus
FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl, bool Final=false)
Definition: SemaDecl.cpp:19620
clang::Sema::FunctionEmissionStatus::Emitted
@ Emitted
clang
Definition: CalledOnceCheck.h:17
clang::Type::isAnyPointerType
bool isAnyPointerType() const
Definition: Type.h:6887
clang::Type::isArrayType
bool isArrayType() const
Definition: Type.h:6949
Mangle.h
clang::Sema::checkSYCLDeviceFunction
bool checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee)
Check whether we're allowed to call Callee from the current context.
Definition: SemaSYCL.cpp:36
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1904