xref: /freebsd/contrib/llvm-project/clang/include/clang/Sema/SemaBase.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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   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:
ImmediateDiagBuilder(DiagnosticBuilder & DB,Sema & SemaRef,unsigned DiagID)61     ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
62         : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
ImmediateDiagBuilder(DiagnosticBuilder && DB,Sema & SemaRef,unsigned 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 
isImmediate()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 
ExprError(const SemaDiagnosticBuilder &)183     friend ExprResult ExprError(const SemaDiagnosticBuilder &) {
184       return ExprError();
185     }
StmtError(const SemaDiagnosticBuilder &)186     friend StmtResult StmtError(const SemaDiagnosticBuilder &) {
187       return StmtError();
188     }
ExprResult()189     operator ExprResult() const { return ExprError(); }
StmtResult()190     operator StmtResult() const { return StmtError(); }
TypeResult()191     operator TypeResult() const { return TypeError(); }
DeclResult()192     operator DeclResult() const { return DeclResult(true); }
MemInitResult()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