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