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"
20#include "clang/Basic/PartialDiagnostic.h"
21#include "clang/Basic/SourceLocation.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
29namespace clang {
30
31class ASTContext;
32class DiagnosticsEngine;
33class LangOptions;
34class Sema;
35
36class SemaBase {
37public:
38 SemaBase(Sema &S);
39
40 Sema &SemaRef;
41
42 ASTContext &getASTContext() const;
43 DiagnosticsEngine &getDiagnostics() const;
44 const LangOptions &getLangOpts() const;
45 DeclContext *getCurContext() const;
46
47 /// Helper class that creates diagnostics with optional
48 /// template instantiation stacks.
49 ///
50 /// This class provides a wrapper around the basic DiagnosticBuilder
51 /// class that emits diagnostics. ImmediateDiagBuilder is
52 /// responsible for emitting the diagnostic (as DiagnosticBuilder
53 /// does) and, if the diagnostic comes from inside a template
54 /// instantiation, printing the template instantiation stack as
55 /// well.
56 class ImmediateDiagBuilder : public DiagnosticBuilder {
57 Sema &SemaRef;
58 unsigned DiagID;
59
60 public:
61 ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
62 : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
63 ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID)
64 : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
65
66 // This is a cunning lie. DiagnosticBuilder actually performs move
67 // construction in its copy constructor (but due to varied uses, it's not
68 // possible to conveniently express this as actual move construction). So
69 // the default copy ctor here is fine, because the base class disables the
70 // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op
71 // in that case anwyay.
72 ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default;
73
74 ~ImmediateDiagBuilder();
75
76 /// Teach operator<< to produce an object of the correct type.
77 template <typename T>
78 friend const ImmediateDiagBuilder &
79 operator<<(const ImmediateDiagBuilder &Diag, const T &Value) {
80 const DiagnosticBuilder &BaseDiag = Diag;
81 BaseDiag << Value;
82 return Diag;
83 }
84
85 // It is necessary to limit this to rvalue reference to avoid calling this
86 // function with a bitfield lvalue argument since non-const reference to
87 // bitfield is not allowed.
88 template <typename T,
89 typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
90 const ImmediateDiagBuilder &operator<<(T &&V) const {
91 const DiagnosticBuilder &BaseDiag = *this;
92 BaseDiag << std::move(V);
93 return *this;
94 }
95 };
96
97 /// A generic diagnostic builder for errors which may or may not be deferred.
98 ///
99 /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch)
100 /// which are not allowed to appear inside __device__ functions and are
101 /// allowed to appear in __host__ __device__ functions only if the host+device
102 /// function is never codegen'ed.
103 ///
104 /// To handle this, we use the notion of "deferred diagnostics", where we
105 /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed.
106 ///
107 /// This class lets you emit either a regular diagnostic, a deferred
108 /// diagnostic, or no diagnostic at all, according to an argument you pass to
109 /// its constructor, thus simplifying the process of creating these "maybe
110 /// deferred" diagnostics.
111 class SemaDiagnosticBuilder {
112 public:
113 enum Kind {
114 /// Emit no diagnostics.
115 K_Nop,
116 /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
117 K_Immediate,
118 /// Emit the diagnostic immediately, and, if it's a warning or error, also
119 /// emit a call stack showing how this function can be reached by an a
120 /// priori known-emitted function.
121 K_ImmediateWithCallStack,
122 /// Create a deferred diagnostic, which is emitted only if the function
123 /// it's attached to is codegen'ed. Also emit a call stack as with
124 /// K_ImmediateWithCallStack.
125 K_Deferred
126 };
127
128 SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID,
129 const FunctionDecl *Fn, Sema &S);
130 SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D);
131 SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default;
132
133 // The copy and move assignment operator is defined as deleted pending
134 // further motivation.
135 SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete;
136 SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete;
137
138 ~SemaDiagnosticBuilder();
139
140 bool isImmediate() const { return ImmediateDiag.has_value(); }
141
142 /// Convertible to bool: True if we immediately emitted an error, false if
143 /// we didn't emit an error or we created a deferred error.
144 ///
145 /// Example usage:
146 ///
147 /// if (SemaDiagnosticBuilder(...) << foo << bar)
148 /// return ExprError();
149 ///
150 /// But see DiagIfDeviceCode() and DiagIfHostCode() -- you probably
151 /// want to use these instead of creating a SemaDiagnosticBuilder yourself.
152 operator bool() const { return isImmediate(); }
153
154 template <typename T>
155 friend const SemaDiagnosticBuilder &
156 operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) {
157 if (Diag.ImmediateDiag)
158 *Diag.ImmediateDiag << Value;
159 else if (Diag.PartialDiagId)
160 Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second
161 << Value;
162 return Diag;
163 }
164
165 // It is necessary to limit this to rvalue reference to avoid calling this
166 // function with a bitfield lvalue argument since non-const reference to
167 // bitfield is not allowed.
168 template <typename T,
169 typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
170 const SemaDiagnosticBuilder &operator<<(T &&V) const {
171 if (ImmediateDiag)
172 *ImmediateDiag << std::move(V);
173 else if (PartialDiagId)
174 getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V);
175 return *this;
176 }
177
178 friend const SemaDiagnosticBuilder &
179 operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD);
180
181 void AddFixItHint(const FixItHint &Hint) const;
182
183 friend ExprResult ExprError(const SemaDiagnosticBuilder &) {
184 return ExprError();
185 }
186 friend StmtResult StmtError(const SemaDiagnosticBuilder &) {
187 return StmtError();
188 }
189 operator ExprResult() const { return ExprError(); }
190 operator StmtResult() const { return StmtError(); }
191 operator TypeResult() const { return TypeError(); }
192 operator DeclResult() const { return DeclResult(true); }
193 operator MemInitResult() const { return MemInitResult(true); }
194
195 using DeferredDiagnosticsType =
196 llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>,
197 std::vector<PartialDiagnosticAt>>;
198
199 private:
200 Sema &S;
201 SourceLocation Loc;
202 unsigned DiagID;
203 const FunctionDecl *Fn;
204 bool ShowCallStack;
205
206 // Invariant: At most one of these Optionals has a value.
207 // FIXME: Switch these to a Variant once that exists.
208 std::optional<ImmediateDiagBuilder> ImmediateDiag;
209 std::optional<unsigned> PartialDiagId;
210
211 DeferredDiagnosticsType &getDeviceDeferredDiags() const;
212 };
213
214 /// Emit a diagnostic.
215 SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID,
216 bool DeferHint = false);
217
218 /// Emit a partial diagnostic.
219 SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD,
220 bool DeferHint = false);
221
222 /// Emit a compatibility diagnostic.
223 SemaDiagnosticBuilder DiagCompat(SourceLocation Loc, unsigned CompatDiagId,
224 bool DeferHint = false);
225
226 /// Build a partial diagnostic.
227 PartialDiagnostic PDiag(unsigned DiagID = 0);
228};
229
230} // namespace clang
231
232#endif
233

source code of clang/include/clang/Sema/SemaBase.h