Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:04

0001 //===--- SemaBase.h - Common utilities for semantic analysis-----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file defines the SemaBase class, which provides utilities for Sema
0010 // and its parts like SemaOpenACC.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_SEMA_SEMABASE_H
0015 #define LLVM_CLANG_SEMA_SEMABASE_H
0016 
0017 #include "clang/AST/Decl.h"
0018 #include "clang/AST/Redeclarable.h"
0019 #include "clang/Basic/Diagnostic.h"
0020 #include "clang/Basic/PartialDiagnostic.h"
0021 #include "clang/Basic/SourceLocation.h"
0022 #include "clang/Sema/Ownership.h"
0023 #include "llvm/ADT/DenseMap.h"
0024 #include <optional>
0025 #include <type_traits>
0026 #include <utility>
0027 #include <vector>
0028 
0029 namespace clang {
0030 
0031 class ASTContext;
0032 class DiagnosticsEngine;
0033 class LangOptions;
0034 class Sema;
0035 
0036 class SemaBase {
0037 public:
0038   SemaBase(Sema &S);
0039 
0040   Sema &SemaRef;
0041 
0042   ASTContext &getASTContext() const;
0043   DiagnosticsEngine &getDiagnostics() const;
0044   const LangOptions &getLangOpts() const;
0045 
0046   /// Helper class that creates diagnostics with optional
0047   /// template instantiation stacks.
0048   ///
0049   /// This class provides a wrapper around the basic DiagnosticBuilder
0050   /// class that emits diagnostics. ImmediateDiagBuilder is
0051   /// responsible for emitting the diagnostic (as DiagnosticBuilder
0052   /// does) and, if the diagnostic comes from inside a template
0053   /// instantiation, printing the template instantiation stack as
0054   /// well.
0055   class ImmediateDiagBuilder : public DiagnosticBuilder {
0056     Sema &SemaRef;
0057     unsigned DiagID;
0058 
0059   public:
0060     ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID)
0061         : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
0062     ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID)
0063         : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {}
0064 
0065     // This is a cunning lie. DiagnosticBuilder actually performs move
0066     // construction in its copy constructor (but due to varied uses, it's not
0067     // possible to conveniently express this as actual move construction). So
0068     // the default copy ctor here is fine, because the base class disables the
0069     // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op
0070     // in that case anwyay.
0071     ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default;
0072 
0073     ~ImmediateDiagBuilder();
0074 
0075     /// Teach operator<< to produce an object of the correct type.
0076     template <typename T>
0077     friend const ImmediateDiagBuilder &
0078     operator<<(const ImmediateDiagBuilder &Diag, const T &Value) {
0079       const DiagnosticBuilder &BaseDiag = Diag;
0080       BaseDiag << Value;
0081       return Diag;
0082     }
0083 
0084     // It is necessary to limit this to rvalue reference to avoid calling this
0085     // function with a bitfield lvalue argument since non-const reference to
0086     // bitfield is not allowed.
0087     template <typename T,
0088               typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
0089     const ImmediateDiagBuilder &operator<<(T &&V) const {
0090       const DiagnosticBuilder &BaseDiag = *this;
0091       BaseDiag << std::move(V);
0092       return *this;
0093     }
0094   };
0095 
0096   /// A generic diagnostic builder for errors which may or may not be deferred.
0097   ///
0098   /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch)
0099   /// which are not allowed to appear inside __device__ functions and are
0100   /// allowed to appear in __host__ __device__ functions only if the host+device
0101   /// function is never codegen'ed.
0102   ///
0103   /// To handle this, we use the notion of "deferred diagnostics", where we
0104   /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed.
0105   ///
0106   /// This class lets you emit either a regular diagnostic, a deferred
0107   /// diagnostic, or no diagnostic at all, according to an argument you pass to
0108   /// its constructor, thus simplifying the process of creating these "maybe
0109   /// deferred" diagnostics.
0110   class SemaDiagnosticBuilder {
0111   public:
0112     enum Kind {
0113       /// Emit no diagnostics.
0114       K_Nop,
0115       /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
0116       K_Immediate,
0117       /// Emit the diagnostic immediately, and, if it's a warning or error, also
0118       /// emit a call stack showing how this function can be reached by an a
0119       /// priori known-emitted function.
0120       K_ImmediateWithCallStack,
0121       /// Create a deferred diagnostic, which is emitted only if the function
0122       /// it's attached to is codegen'ed.  Also emit a call stack as with
0123       /// K_ImmediateWithCallStack.
0124       K_Deferred
0125     };
0126 
0127     SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID,
0128                           const FunctionDecl *Fn, Sema &S);
0129     SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D);
0130     SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default;
0131 
0132     // The copy and move assignment operator is defined as deleted pending
0133     // further motivation.
0134     SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete;
0135     SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete;
0136 
0137     ~SemaDiagnosticBuilder();
0138 
0139     bool isImmediate() const { return ImmediateDiag.has_value(); }
0140 
0141     /// Convertible to bool: True if we immediately emitted an error, false if
0142     /// we didn't emit an error or we created a deferred error.
0143     ///
0144     /// Example usage:
0145     ///
0146     ///   if (SemaDiagnosticBuilder(...) << foo << bar)
0147     ///     return ExprError();
0148     ///
0149     /// But see DiagIfDeviceCode() and DiagIfHostCode() -- you probably
0150     /// want to use these instead of creating a SemaDiagnosticBuilder yourself.
0151     operator bool() const { return isImmediate(); }
0152 
0153     template <typename T>
0154     friend const SemaDiagnosticBuilder &
0155     operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) {
0156       if (Diag.ImmediateDiag)
0157         *Diag.ImmediateDiag << Value;
0158       else if (Diag.PartialDiagId)
0159         Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second
0160             << Value;
0161       return Diag;
0162     }
0163 
0164     // It is necessary to limit this to rvalue reference to avoid calling this
0165     // function with a bitfield lvalue argument since non-const reference to
0166     // bitfield is not allowed.
0167     template <typename T,
0168               typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>>
0169     const SemaDiagnosticBuilder &operator<<(T &&V) const {
0170       if (ImmediateDiag)
0171         *ImmediateDiag << std::move(V);
0172       else if (PartialDiagId)
0173         getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V);
0174       return *this;
0175     }
0176 
0177     friend const SemaDiagnosticBuilder &
0178     operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD);
0179 
0180     void AddFixItHint(const FixItHint &Hint) const;
0181 
0182     friend ExprResult ExprError(const SemaDiagnosticBuilder &) {
0183       return ExprError();
0184     }
0185     friend StmtResult StmtError(const SemaDiagnosticBuilder &) {
0186       return StmtError();
0187     }
0188     operator ExprResult() const { return ExprError(); }
0189     operator StmtResult() const { return StmtError(); }
0190     operator TypeResult() const { return TypeError(); }
0191     operator DeclResult() const { return DeclResult(true); }
0192     operator MemInitResult() const { return MemInitResult(true); }
0193 
0194     using DeferredDiagnosticsType =
0195         llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>,
0196                        std::vector<PartialDiagnosticAt>>;
0197 
0198   private:
0199     Sema &S;
0200     SourceLocation Loc;
0201     unsigned DiagID;
0202     const FunctionDecl *Fn;
0203     bool ShowCallStack;
0204 
0205     // Invariant: At most one of these Optionals has a value.
0206     // FIXME: Switch these to a Variant once that exists.
0207     std::optional<ImmediateDiagBuilder> ImmediateDiag;
0208     std::optional<unsigned> PartialDiagId;
0209 
0210     DeferredDiagnosticsType &getDeviceDeferredDiags() const;
0211   };
0212 
0213   /// Emit a diagnostic.
0214   SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID,
0215                              bool DeferHint = false);
0216 
0217   /// Emit a partial diagnostic.
0218   SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD,
0219                              bool DeferHint = false);
0220 
0221   /// Build a partial diagnostic.
0222   PartialDiagnostic PDiag(unsigned DiagID = 0);
0223 };
0224 
0225 } // namespace clang
0226 
0227 #endif