xref: /freebsd/contrib/llvm-project/clang/include/clang/Sema/SemaBase.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
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 
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:
ImmediateDiagBuilder(DiagnosticBuilder & DB,Sema & SemaRef,unsigned DiagID)60     ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
61         : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
ImmediateDiagBuilder(DiagnosticBuilder && DB,Sema & SemaRef,unsigned 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 
isImmediate()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 
ExprError(const SemaDiagnosticBuilder &)182     friend ExprResult ExprError(const SemaDiagnosticBuilder &) {
183       return ExprError();
184     }
StmtError(const SemaDiagnosticBuilder &)185     friend StmtResult StmtError(const SemaDiagnosticBuilder &) {
186       return StmtError();
187     }
ExprResult()188     operator ExprResult() const { return ExprError(); }
StmtResult()189     operator StmtResult() const { return StmtError(); }
TypeResult()190     operator TypeResult() const { return TypeError(); }
DeclResult()191     operator DeclResult() const { return DeclResult(true); }
MemInitResult()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   /// Build a partial diagnostic.
222   PartialDiagnostic PDiag(unsigned DiagID = 0);
223 };
224 
225 } // namespace clang
226 
227 #endif
228