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
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.
55 class ImmediateDiagBuilder : public DiagnosticBuilder {
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.
71 ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default;
72
73 ~ImmediateDiagBuilder();
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 /// A generic diagnostic builder for errors which may or may not be deferred.
97 ///
98 /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch)
99 /// which are not allowed to appear inside __device__ functions and are
100 /// allowed to appear in __host__ __device__ functions only if the host+device
101 /// function is never codegen'ed.
102 ///
103 /// To handle this, we use the notion of "deferred diagnostics", where we
104 /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed.
105 ///
106 /// This class lets you emit either a regular diagnostic, a deferred
107 /// diagnostic, or no diagnostic at all, according to an argument you pass to
108 /// its constructor, thus simplifying the process of creating these "maybe
109 /// deferred" diagnostics.
110 class SemaDiagnosticBuilder {
111 public:
112 enum Kind {
113 /// Emit no diagnostics.
114 K_Nop,
115 /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
116 K_Immediate,
117 /// Emit the diagnostic immediately, and, if it's a warning or error, also
118 /// emit a call stack showing how this function can be reached by an a
119 /// priori known-emitted function.
120 K_ImmediateWithCallStack,
121 /// Create a deferred diagnostic, which is emitted only if the function
122 /// it's attached to is codegen'ed. Also emit a call stack as with
123 /// K_ImmediateWithCallStack.
124 K_Deferred
125 };
126
127 SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID,
128 const FunctionDecl *Fn, Sema &S);
129 SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D);
130 SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default;
131
132 // The copy and move assignment operator is defined as deleted pending
133 // further motivation.
134 SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete;
135 SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete;
136
137 ~SemaDiagnosticBuilder();
138
139 bool isImmediate() const { return ImmediateDiag.has_value(); }
140
141 /// Convertible to bool: True if we immediately emitted an error, false if
142 /// we didn't emit an error or we created a deferred error.
143 ///
144 /// Example usage:
145 ///
146 /// if (SemaDiagnosticBuilder(...) << foo << bar)
147 /// return ExprError();
148 ///
149 /// But see DiagIfDeviceCode() and DiagIfHostCode() -- you probably
150 /// want to use these instead of creating a SemaDiagnosticBuilder yourself.
151 operator bool() const { return isImmediate(); }
152
153 template <typename T>
154 friend const SemaDiagnosticBuilder &
155 operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) {
156 if (Diag.ImmediateDiag)
157 *Diag.ImmediateDiag << Value;
158 else if (Diag.PartialDiagId)
159 Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second
160 << Value;
161 return Diag;
162 }
163
164 // It is necessary to limit this to rvalue reference to avoid calling this
165 // function with a bitfield lvalue argument since non-const reference to
166 // bitfield is not allowed.
167 template <typename T,
168 typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
169 const SemaDiagnosticBuilder &operator<<(T &&V) const {
170 if (ImmediateDiag)
171 *ImmediateDiag << std::move(V);
172 else if (PartialDiagId)
173 getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V);
174 return *this;
175 }
176
177 friend const SemaDiagnosticBuilder &
178 operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD);
179
180 void AddFixItHint(const FixItHint &Hint) const;
181
182 friend ExprResult ExprError(const SemaDiagnosticBuilder &) {
183 return ExprError();
184 }
185 friend StmtResult StmtError(const SemaDiagnosticBuilder &) {
186 return StmtError();
187 }
188 operator ExprResult() const { return ExprError(); }
189 operator StmtResult() const { return StmtError(); }
190 operator TypeResult() const { return TypeError(); }
191 operator DeclResult() const { return DeclResult(true); }
192 operator MemInitResult() const { return MemInitResult(true); }
193
194 using DeferredDiagnosticsType =
195 llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>,
196 std::vector<PartialDiagnosticAt>>;
197
198 private:
199 Sema &S;
200 SourceLocation Loc;
201 unsigned DiagID;
202 const FunctionDecl *Fn;
203 bool ShowCallStack;
204
205 // Invariant: At most one of these Optionals has a value.
206 // FIXME: Switch these to a Variant once that exists.
207 std::optional<ImmediateDiagBuilder> ImmediateDiag;
208 std::optional<unsigned> PartialDiagId;
209
210 DeferredDiagnosticsType &getDeviceDeferredDiags() const;
211 };
212
213 /// Emit a diagnostic.
214 SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID,
215 bool DeferHint = false);
216
217 /// Emit a partial diagnostic.
218 SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD,
219 bool DeferHint = false);
220};
221
222} // namespace clang
223
224#endif
225

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