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