clang  19.0.0git
SemaBase.h
Go to the documentation of this file.
1 //===--- SemaBase.h - Common utilities for semantic analysis-----*- C++ -*-===//
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 //
9 // This file defines the SemaBase class, which provides utilities for Sema
10 // and its parts like SemaOpenACC.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_SEMA_SEMABASE_H
15 #define LLVM_CLANG_SEMA_SEMABASE_H
16 
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/Redeclarable.h"
19 #include "clang/Basic/Diagnostic.h"
22 #include "clang/Sema/Ownership.h"
23 #include "llvm/ADT/DenseMap.h"
24 #include <optional>
25 #include <type_traits>
26 #include <utility>
27 #include <vector>
28 
29 namespace clang {
30 
31 class ASTContext;
32 class DiagnosticsEngine;
33 class LangOptions;
34 class Sema;
35 
36 class SemaBase {
37 public:
38  SemaBase(Sema &S);
39 
41 
42  ASTContext &getASTContext() const;
44  const LangOptions &getLangOpts() const;
45 
46  /// Helper class that creates diagnostics with optional
47  /// template instantiation stacks.
48  ///
49  /// This class provides a wrapper around the basic DiagnosticBuilder
50  /// class that emits diagnostics. ImmediateDiagBuilder is
51  /// responsible for emitting the diagnostic (as DiagnosticBuilder
52  /// does) and, if the diagnostic comes from inside a template
53  /// instantiation, printing the template instantiation stack as
54  /// well.
56  Sema &SemaRef;
57  unsigned DiagID;
58 
59  public:
60  ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
61  : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
62  ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID)
63  : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
64 
65  // This is a cunning lie. DiagnosticBuilder actually performs move
66  // construction in its copy constructor (but due to varied uses, it's not
67  // possible to conveniently express this as actual move construction). So
68  // the default copy ctor here is fine, because the base class disables the
69  // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op
70  // in that case anwyay.
72 
74 
75  /// Teach operator<< to produce an object of the correct type.
76  template <typename T>
77  friend const ImmediateDiagBuilder &
78  operator<<(const ImmediateDiagBuilder &Diag, const T &Value) {
79  const DiagnosticBuilder &BaseDiag = Diag;
80  BaseDiag << Value;
81  return Diag;
82  }
83 
84  // It is necessary to limit this to rvalue reference to avoid calling this
85  // function with a bitfield lvalue argument since non-const reference to
86  // bitfield is not allowed.
87  template <typename T,
88  typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
89  const ImmediateDiagBuilder &operator<<(T &&V) const {
90  const DiagnosticBuilder &BaseDiag = *this;
91  BaseDiag << std::move(V);
92  return *this;
93  }
94  };
95 
96  /// Bitmask to contain the list of reasons a single diagnostic should be
97  /// emitted, based on its language. This permits multiple offload systems
98  /// to coexist in the same translation unit.
100  /// Diagnostic doesn't apply to anything. Included for completeness, but
101  /// should make this a no-op.
102  None = 0,
103  /// OpenMP specific diagnostic.
104  OmpDevice = 1 << 0,
105  OmpHost = 1 << 1,
107  /// CUDA specific diagnostics.
108  CudaDevice = 1 << 2,
109  CudaHost = 1 << 3,
111  /// SYCL specific diagnostic.
112  Sycl = 1 << 4,
113  /// ESIMD specific diagnostic.
114  Esimd = 1 << 5,
115  /// A flag representing 'all'. This can be used to avoid the check
116  /// all-together and make this behave as it did before the
117  /// DiagnosticReason was added (that is, unconditionally emit).
118  /// Note: This needs to be updated if any flags above are added.
119  All = OmpAll | CudaAll | Sycl | Esimd,
120 
121  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/All)
122  };
123 
124 private:
125  // A collection of a pair of undefined functions and their callers known
126  // to be reachable from a routine on the device (kernel or device function).
127  typedef std::pair<const FunctionDecl *, const FunctionDecl *> CallPair;
128  llvm::SmallVector<CallPair> UndefinedReachableFromSyclDevice;
129 
130 public:
131  // Helper routine to add a pair of Callee-Caller pair of FunctionDecl *
132  // to UndefinedReachableFromSyclDevice.
134  const FunctionDecl *Caller) {
135  UndefinedReachableFromSyclDevice.push_back(std::make_pair(Callee, Caller));
136  }
137  // Helper routine to check if a pair of Callee-Caller FunctionDecl *
138  // is in UndefinedReachableFromSyclDevice.
140  const FunctionDecl *Caller) {
141  return llvm::any_of(UndefinedReachableFromSyclDevice,
142  [Callee, Caller](const CallPair &P) {
143  return P.first == Callee && P.second == Caller;
144  });
145  }
146 
148  public:
151  : Diagnostic(SL, PD), Reason(R) {}
152 
154  DeviceDiagnosticReason getReason() const { return Reason; }
155 
156  private:
158  DeviceDiagnosticReason Reason;
159  };
160 
161  /// A generic diagnostic builder for errors which may or may not be deferred.
162  ///
163  /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch)
164  /// which are not allowed to appear inside __device__ functions and are
165  /// allowed to appear in __host__ __device__ functions only if the host+device
166  /// function is never codegen'ed.
167  ///
168  /// To handle this, we use the notion of "deferred diagnostics", where we
169  /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed.
170  ///
171  /// This class lets you emit either a regular diagnostic, a deferred
172  /// diagnostic, or no diagnostic at all, according to an argument you pass to
173  /// its constructor, thus simplifying the process of creating these "maybe
174  /// deferred" diagnostics.
176  public:
177  enum Kind {
178  /// Emit no diagnostics.
180  /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
182  /// Emit the diagnostic immediately, and, if it's a warning or error, also
183  /// emit a call stack showing how this function can be reached by an a
184  /// priori known-emitted function.
186  /// Create a deferred diagnostic, which is emitted only if the function
187  /// it's attached to is codegen'ed. Also emit a call stack as with
188  /// K_ImmediateWithCallStack.
189  K_Deferred
190  };
191 
192  SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID,
193  const FunctionDecl *Fn, Sema &S, DeviceDiagnosticReason R);
196 
197  // The copy and move assignment operator is defined as deleted pending
198  // further motivation.
201 
203 
204  bool isImmediate() const { return ImmediateDiag.has_value(); }
205 
206  /// Convertible to bool: True if we immediately emitted an error, false if
207  /// we didn't emit an error or we created a deferred error.
208  ///
209  /// Example usage:
210  ///
211  /// if (SemaDiagnosticBuilder(...) << foo << bar)
212  /// return ExprError();
213  ///
214  /// But see DiagIfDeviceCode() and DiagIfHostCode() -- you probably
215  /// want to use these instead of creating a SemaDiagnosticBuilder yourself.
216  operator bool() const { return isImmediate(); }
217 
218  template <typename T>
219  friend const SemaDiagnosticBuilder &
220  operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) {
221  if (Diag.ImmediateDiag)
222  *Diag.ImmediateDiag << Value;
223  else if (Diag.PartialDiagId)
224  Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId]
225  .getDiag()
226  .second
227  << Value;
228  return Diag;
229  }
230 
231  // It is necessary to limit this to rvalue reference to avoid calling this
232  // function with a bitfield lvalue argument since non-const reference to
233  // bitfield is not allowed.
234  template <typename T,
235  typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
237  if (ImmediateDiag)
238  *ImmediateDiag << std::move(V);
239  else if (PartialDiagId)
240  getDeviceDeferredDiags()[Fn][*PartialDiagId].getDiag().second
241  << std::move(V);
242  return *this;
243  }
244 
245  friend const SemaDiagnosticBuilder &
247 
248  void AddFixItHint(const FixItHint &Hint) const;
249 
251  return ExprError();
252  }
254  return StmtError();
255  }
256  operator ExprResult() const { return ExprError(); }
257  operator StmtResult() const { return StmtError(); }
258  operator TypeResult() const { return TypeError(); }
259  operator DeclResult() const { return DeclResult(true); }
260  operator MemInitResult() const { return MemInitResult(true); }
261 
263  llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>,
264  std::vector<DeviceDeferredDiagnostic>>;
265 
266  private:
267  Sema &S;
268  SourceLocation Loc;
269  unsigned DiagID;
270  const FunctionDecl *Fn;
271  bool ShowCallStack;
272 
273  // Invariant: At most one of these Optionals has a value.
274  // FIXME: Switch these to a Variant once that exists.
275  std::optional<ImmediateDiagBuilder> ImmediateDiag;
276  std::optional<unsigned> PartialDiagId;
277 
278  DeferredDiagnosticsType &getDeviceDeferredDiags() const;
279  };
280 
281  /// Emit a diagnostic.
282  SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID,
283  bool DeferHint = false);
284 
285  /// Emit a partial diagnostic.
287  bool DeferHint = false);
288 };
289 
290 } // namespace clang
291 
292 #endif
#define V(N, I)
Definition: ASTContext.h:3299
StringRef P
Defines the Diagnostic-related interfaces.
Implements a partial diagnostic that can be emitted anwyhere in a DiagnosticBuilder stream.
SourceLocation Loc
Definition: SemaObjC.cpp:755
Defines the clang::SourceLocation class and associated facilities.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
A little helper class used to produce diagnostics.
Definition: Diagnostic.h:1277
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1577
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:193
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
Definition: Diagnostic.h:72
Represents a function declaration or definition.
Definition: Decl.h:1972
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:482
DeviceDiagnosticReason getReason() const
Definition: SemaBase.h:154
DeviceDeferredDiagnostic(SourceLocation SL, const PartialDiagnostic &PD, DeviceDiagnosticReason R)
Definition: SemaBase.h:149
PartialDiagnosticAt & getDiag()
Definition: SemaBase.h:153
Helper class that creates diagnostics with optional template instantiation stacks.
Definition: SemaBase.h:55
friend const ImmediateDiagBuilder & operator<<(const ImmediateDiagBuilder &Diag, const T &Value)
Teach operator<< to produce an object of the correct type.
Definition: SemaBase.h:78
ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID)
Definition: SemaBase.h:62
ImmediateDiagBuilder(const ImmediateDiagBuilder &)=default
ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
Definition: SemaBase.h:60
const ImmediateDiagBuilder & operator<<(T &&V) const
Definition: SemaBase.h:89
A generic diagnostic builder for errors which may or may not be deferred.
Definition: SemaBase.h:175
SemaDiagnosticBuilder(const SemaDiagnosticBuilder &)=default
@ K_Deferred
Create a deferred diagnostic, which is emitted only if the function it's attached to is codegen'ed.
Definition: SemaBase.h:189
@ K_ImmediateWithCallStack
Emit the diagnostic immediately, and, if it's a warning or error, also emit a call stack showing how ...
Definition: SemaBase.h:185
@ K_Immediate
Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
Definition: SemaBase.h:181
void AddFixItHint(const FixItHint &Hint) const
Definition: SemaBase.cpp:43
const SemaDiagnosticBuilder & operator<<(T &&V) const
Definition: SemaBase.h:236
SemaDiagnosticBuilder & operator=(const SemaDiagnosticBuilder &)=delete
SemaDiagnosticBuilder & operator=(SemaDiagnosticBuilder &&)=delete
SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, const FunctionDecl *Fn, Sema &S, DeviceDiagnosticReason R)
friend StmtResult StmtError(const SemaDiagnosticBuilder &)
Definition: SemaBase.h:253
llvm::DenseMap< CanonicalDeclPtr< const FunctionDecl >, std::vector< DeviceDeferredDiagnostic > > DeferredDiagnosticsType
Definition: SemaBase.h:264
friend const SemaDiagnosticBuilder & operator<<(const SemaDiagnosticBuilder &Diag, const T &Value)
Definition: SemaBase.h:220
friend ExprResult ExprError(const SemaDiagnosticBuilder &)
Definition: SemaBase.h:250
SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D)
bool isFDReachableFromSyclDevice(const FunctionDecl *Callee, const FunctionDecl *Caller)
Definition: SemaBase.h:139
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Definition: SemaBase.cpp:57
DeviceDiagnosticReason
Bitmask to contain the list of reasons a single diagnostic should be emitted, based on its language.
Definition: SemaBase.h:99
@ Sycl
SYCL specific diagnostic.
@ CudaDevice
CUDA specific diagnostics.
@ Esimd
ESIMD specific diagnostic.
@ None
Diagnostic doesn't apply to anything.
@ All
A flag representing 'all'.
@ OmpDevice
OpenMP specific diagnostic.
void addFDToReachableFromSyclDevice(const FunctionDecl *Callee, const FunctionDecl *Caller)
Definition: SemaBase.h:133
SemaBase(Sema &S)
Definition: SemaBase.cpp:7
ASTContext & getASTContext() const
Definition: SemaBase.cpp:9
Sema & SemaRef
Definition: SemaBase.h:40
const LangOptions & getLangOpts() const
Definition: SemaBase.cpp:11
DiagnosticsEngine & getDiagnostics() const
Definition: SemaBase.cpp:10
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:462
Encodes a location in the source.
The JSON file list parser is used to communicate input to InstallAPI.
TypeResult TypeError()
Definition: Ownership.h:266
ActionResult< CXXCtorInitializer * > MemInitResult
Definition: Ownership.h:252
ActionResult< Expr * > ExprResult
Definition: Ownership.h:248
ActionResult< Stmt * > StmtResult
Definition: Ownership.h:249
ActionResult< ParsedType > TypeResult
Definition: Ownership.h:250
const FunctionProtoType * T
std::pair< SourceLocation, PartialDiagnostic > PartialDiagnosticAt
A partial diagnostic along with the source location where this diagnostic occurs.
ActionResult< Decl * > DeclResult
Definition: Ownership.h:254
#define bool
Definition: stdbool.h:24