clang 17.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
15using 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
52static 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}
static bool isZeroSizedArray(Sema &SemaRef, QualType Ty)
Definition: SemaSYCL.cpp:52
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2703
Represents a function declaration or definition.
Definition: Decl.h:1917
A (possibly-)qualified type.
Definition: Type.h:736
A generic diagnostic builder for errors which may or may not be deferred.
Definition: Sema.h:1760
@ K_Nop
Emit no diagnostics.
Definition: Sema.h:1764
@ K_Deferred
Create a deferred diagnostic, which is emitted only if the function it's attached to is codegen'ed.
Definition: Sema.h:1774
@ K_ImmediateWithCallStack
Emit the diagnostic immediately, and, if it's a warning or error, also emit a call stack showing how ...
Definition: Sema.h:1770
@ K_Immediate
Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
Definition: Sema.h:1766
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:356
ASTContext & getASTContext() const
Definition: Sema.h:1652
bool checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee)
Check whether we're allowed to call Callee from the current context.
Definition: SemaSYCL.cpp:36
const LangOptions & getLangOpts() const
Definition: Sema.h:1645
DeclContext * getCurLexicalContext() const
Definition: Sema.h:13792
void deepTypeCheckForSYCLDevice(SourceLocation UsedAt, llvm::DenseSet< QualType > Visited, ValueDecl *DeclToCheck)
Definition: SemaSYCL.cpp:58
bool isConstantEvaluated() const
Definition: Sema.h:1048
bool isUnevaluatedContext() const
Determines whether we are currently in a context that is not evaluated as per C++ [expr] p5.
Definition: Sema.h:9689
FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl, bool Final=false)
Definition: SemaDecl.cpp:19883
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
Encodes a location in the source.
bool isArrayType() const
Definition: Type.h:6976
bool isReferenceType() const
Definition: Type.h:6922
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
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:629
bool isAnyPointerType() const
Definition: Type.h:6914
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1787
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:701