Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:49

0001 //===--- DiagnosticIDs.h - Diagnostic IDs Handling --------------*- 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 /// \file
0010 /// Defines the Diagnostic IDs-related interfaces.
0011 ///
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
0015 #define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
0016 
0017 #include "clang/Basic/DiagnosticCategories.h"
0018 #include "clang/Basic/LLVM.h"
0019 #include "llvm/ADT/IntrusiveRefCntPtr.h"
0020 #include "llvm/ADT/StringRef.h"
0021 #include "llvm/Support/ErrorHandling.h"
0022 #include <optional>
0023 #include <vector>
0024 
0025 namespace clang {
0026   class DiagnosticsEngine;
0027   class DiagnosticBuilder;
0028   class SourceLocation;
0029 
0030   // Import the diagnostic enums themselves.
0031   namespace diag {
0032     enum class Group;
0033 
0034     // Size of each of the diagnostic categories.
0035     enum {
0036       DIAG_SIZE_COMMON        =  300,
0037       DIAG_SIZE_DRIVER        =  400,
0038       DIAG_SIZE_FRONTEND      =  200,
0039       DIAG_SIZE_SERIALIZATION =  120,
0040       DIAG_SIZE_LEX           =  400,
0041       DIAG_SIZE_PARSE         =  700,
0042       DIAG_SIZE_AST           =  300,
0043       DIAG_SIZE_COMMENT       =  100,
0044       DIAG_SIZE_CROSSTU       =  100,
0045       DIAG_SIZE_SEMA          = 5000,
0046       DIAG_SIZE_ANALYSIS      =  100,
0047       DIAG_SIZE_REFACTORING   = 1000,
0048       DIAG_SIZE_INSTALLAPI    =  100,
0049     };
0050     // Start position for diagnostics.
0051     enum {
0052       DIAG_START_COMMON        =                          0,
0053       DIAG_START_DRIVER        = DIAG_START_COMMON        + static_cast<int>(DIAG_SIZE_COMMON),
0054       DIAG_START_FRONTEND      = DIAG_START_DRIVER        + static_cast<int>(DIAG_SIZE_DRIVER),
0055       DIAG_START_SERIALIZATION = DIAG_START_FRONTEND      + static_cast<int>(DIAG_SIZE_FRONTEND),
0056       DIAG_START_LEX           = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
0057       DIAG_START_PARSE         = DIAG_START_LEX           + static_cast<int>(DIAG_SIZE_LEX),
0058       DIAG_START_AST           = DIAG_START_PARSE         + static_cast<int>(DIAG_SIZE_PARSE),
0059       DIAG_START_COMMENT       = DIAG_START_AST           + static_cast<int>(DIAG_SIZE_AST),
0060       DIAG_START_CROSSTU       = DIAG_START_COMMENT       + static_cast<int>(DIAG_SIZE_COMMENT),
0061       DIAG_START_SEMA          = DIAG_START_CROSSTU       + static_cast<int>(DIAG_SIZE_CROSSTU),
0062       DIAG_START_ANALYSIS      = DIAG_START_SEMA          + static_cast<int>(DIAG_SIZE_SEMA),
0063       DIAG_START_REFACTORING   = DIAG_START_ANALYSIS      + static_cast<int>(DIAG_SIZE_ANALYSIS),
0064       DIAG_START_INSTALLAPI    = DIAG_START_REFACTORING   + static_cast<int>(DIAG_SIZE_REFACTORING),
0065       DIAG_UPPER_LIMIT         = DIAG_START_INSTALLAPI    + static_cast<int>(DIAG_SIZE_INSTALLAPI)
0066     };
0067 
0068     class CustomDiagInfo;
0069 
0070     /// All of the diagnostics that can be emitted by the frontend.
0071     typedef unsigned kind;
0072 
0073     // Get typedefs for common diagnostics.
0074     enum {
0075 #define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, CATEGORY,      \
0076              NOWERROR, SHOWINSYSHEADER, SHOWINSYSMACRO, DEFFERABLE)            \
0077   ENUM,
0078 #define COMMONSTART
0079 #include "clang/Basic/DiagnosticCommonKinds.inc"
0080       NUM_BUILTIN_COMMON_DIAGNOSTICS
0081 #undef DIAG
0082     };
0083 
0084     /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
0085     /// to either Ignore (nothing), Remark (emit a remark), Warning
0086     /// (emit a warning) or Error (emit as an error).  It allows clients to
0087     /// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
0088     enum class Severity : uint8_t {
0089       // NOTE: 0 means "uncomputed".
0090       Ignored = 1, ///< Do not present this diagnostic, ignore it.
0091       Remark = 2,  ///< Present this diagnostic as a remark.
0092       Warning = 3, ///< Present this diagnostic as a warning.
0093       Error = 4,   ///< Present this diagnostic as an error.
0094       Fatal = 5    ///< Present this diagnostic as a fatal error.
0095     };
0096 
0097     /// Flavors of diagnostics we can emit. Used to filter for a particular
0098     /// kind of diagnostic (for instance, for -W/-R flags).
0099     enum class Flavor {
0100       WarningOrError, ///< A diagnostic that indicates a problem or potential
0101                       ///< problem. Can be made fatal by -Werror.
0102       Remark          ///< A diagnostic that indicates normal progress through
0103                       ///< compilation.
0104     };
0105   }
0106 
0107 class DiagnosticMapping {
0108   LLVM_PREFERRED_TYPE(diag::Severity)
0109   unsigned Severity : 3;
0110   LLVM_PREFERRED_TYPE(bool)
0111   unsigned IsUser : 1;
0112   LLVM_PREFERRED_TYPE(bool)
0113   unsigned IsPragma : 1;
0114   LLVM_PREFERRED_TYPE(bool)
0115   unsigned HasNoWarningAsError : 1;
0116   LLVM_PREFERRED_TYPE(bool)
0117   unsigned HasNoErrorAsFatal : 1;
0118   LLVM_PREFERRED_TYPE(bool)
0119   unsigned WasUpgradedFromWarning : 1;
0120 
0121 public:
0122   static DiagnosticMapping Make(diag::Severity Severity, bool IsUser,
0123                                 bool IsPragma) {
0124     DiagnosticMapping Result;
0125     Result.Severity = (unsigned)Severity;
0126     Result.IsUser = IsUser;
0127     Result.IsPragma = IsPragma;
0128     Result.HasNoWarningAsError = 0;
0129     Result.HasNoErrorAsFatal = 0;
0130     Result.WasUpgradedFromWarning = 0;
0131     return Result;
0132   }
0133 
0134   diag::Severity getSeverity() const { return (diag::Severity)Severity; }
0135   void setSeverity(diag::Severity Value) { Severity = (unsigned)Value; }
0136 
0137   bool isUser() const { return IsUser; }
0138   bool isPragma() const { return IsPragma; }
0139 
0140   bool isErrorOrFatal() const {
0141     return getSeverity() == diag::Severity::Error ||
0142            getSeverity() == diag::Severity::Fatal;
0143   }
0144 
0145   bool hasNoWarningAsError() const { return HasNoWarningAsError; }
0146   void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; }
0147 
0148   bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; }
0149   void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; }
0150 
0151   /// Whether this mapping attempted to map the diagnostic to a warning, but
0152   /// was overruled because the diagnostic was already mapped to an error or
0153   /// fatal error.
0154   bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; }
0155   void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; }
0156 
0157   /// Serialize this mapping as a raw integer.
0158   unsigned serialize() const {
0159     return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) |
0160            (HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity;
0161   }
0162   /// Deserialize a mapping.
0163   static DiagnosticMapping deserialize(unsigned Bits) {
0164     DiagnosticMapping Result;
0165     Result.IsUser = (Bits >> 7) & 1;
0166     Result.IsPragma = (Bits >> 6) & 1;
0167     Result.HasNoWarningAsError = (Bits >> 5) & 1;
0168     Result.HasNoErrorAsFatal = (Bits >> 4) & 1;
0169     Result.WasUpgradedFromWarning = (Bits >> 3) & 1;
0170     Result.Severity = Bits & 0x7;
0171     return Result;
0172   }
0173 
0174   bool operator==(DiagnosticMapping Other) const {
0175     return serialize() == Other.serialize();
0176   }
0177 };
0178 
0179 /// Used for handling and querying diagnostic IDs.
0180 ///
0181 /// Can be used and shared by multiple Diagnostics for multiple translation units.
0182 class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
0183 public:
0184   /// The level of the diagnostic, after it has been through mapping.
0185   enum Level : uint8_t { Ignored, Note, Remark, Warning, Error, Fatal };
0186 
0187   // Diagnostic classes.
0188   enum Class {
0189     CLASS_INVALID = 0x00,
0190     CLASS_NOTE = 0x01,
0191     CLASS_REMARK = 0x02,
0192     CLASS_WARNING = 0x03,
0193     CLASS_EXTENSION = 0x04,
0194     CLASS_ERROR = 0x05
0195   };
0196 
0197   static bool IsCustomDiag(diag::kind Diag) {
0198     return Diag >= diag::DIAG_UPPER_LIMIT;
0199   }
0200 
0201   class CustomDiagDesc {
0202     LLVM_PREFERRED_TYPE(diag::Severity)
0203     unsigned DefaultSeverity : 3;
0204     LLVM_PREFERRED_TYPE(Class)
0205     unsigned DiagClass : 3;
0206     LLVM_PREFERRED_TYPE(bool)
0207     unsigned ShowInSystemHeader : 1;
0208     LLVM_PREFERRED_TYPE(bool)
0209     unsigned ShowInSystemMacro : 1;
0210     LLVM_PREFERRED_TYPE(bool)
0211     unsigned HasGroup : 1;
0212     diag::Group Group;
0213     std::string Description;
0214 
0215     auto get_as_tuple() const {
0216       return std::tuple(DefaultSeverity, DiagClass, ShowInSystemHeader,
0217                         ShowInSystemMacro, HasGroup, Group,
0218                         std::string_view{Description});
0219     }
0220 
0221   public:
0222     CustomDiagDesc(diag::Severity DefaultSeverity, std::string Description,
0223                    unsigned Class = CLASS_WARNING,
0224                    bool ShowInSystemHeader = false,
0225                    bool ShowInSystemMacro = false,
0226                    std::optional<diag::Group> Group = std::nullopt)
0227         : DefaultSeverity(static_cast<unsigned>(DefaultSeverity)),
0228           DiagClass(Class), ShowInSystemHeader(ShowInSystemHeader),
0229           ShowInSystemMacro(ShowInSystemMacro), HasGroup(Group != std::nullopt),
0230           Group(Group.value_or(diag::Group{})),
0231           Description(std::move(Description)) {}
0232 
0233     std::optional<diag::Group> GetGroup() const {
0234       if (HasGroup)
0235         return Group;
0236       return std::nullopt;
0237     }
0238 
0239     diag::Severity GetDefaultSeverity() const {
0240       return static_cast<diag::Severity>(DefaultSeverity);
0241     }
0242 
0243     Class GetClass() const { return static_cast<Class>(DiagClass); }
0244     std::string_view GetDescription() const { return Description; }
0245     bool ShouldShowInSystemHeader() const { return ShowInSystemHeader; }
0246 
0247     friend bool operator==(const CustomDiagDesc &lhs,
0248                            const CustomDiagDesc &rhs) {
0249       return lhs.get_as_tuple() == rhs.get_as_tuple();
0250     }
0251 
0252     friend bool operator<(const CustomDiagDesc &lhs,
0253                           const CustomDiagDesc &rhs) {
0254       return lhs.get_as_tuple() < rhs.get_as_tuple();
0255     }
0256   };
0257 
0258   struct GroupInfo {
0259     LLVM_PREFERRED_TYPE(diag::Severity)
0260     unsigned Severity : 3;
0261     LLVM_PREFERRED_TYPE(bool)
0262     unsigned HasNoWarningAsError : 1;
0263   };
0264 
0265 private:
0266   /// Information for uniquing and looking up custom diags.
0267   std::unique_ptr<diag::CustomDiagInfo> CustomDiagInfo;
0268   std::unique_ptr<GroupInfo[]> GroupInfos = []() {
0269     auto GIs = std::make_unique<GroupInfo[]>(
0270         static_cast<size_t>(diag::Group::NUM_GROUPS));
0271     for (size_t i = 0; i != static_cast<size_t>(diag::Group::NUM_GROUPS); ++i)
0272       GIs[i] = {{}, false};
0273     return GIs;
0274   }();
0275 
0276 public:
0277   DiagnosticIDs();
0278   ~DiagnosticIDs();
0279 
0280   /// Return an ID for a diagnostic with the specified format string and
0281   /// level.
0282   ///
0283   /// If this is the first request for this diagnostic, it is registered and
0284   /// created, otherwise the existing ID is returned.
0285 
0286   // FIXME: Replace this function with a create-only facilty like
0287   // createCustomDiagIDFromFormatString() to enforce safe usage. At the time of
0288   // writing, nearly all callers of this function were invalid.
0289   unsigned getCustomDiagID(CustomDiagDesc Diag);
0290 
0291   // TODO: Deprecate this once all uses are removed from LLVM
0292   // [[deprecated("Use a CustomDiagDesc instead of a Level")]]
0293   unsigned getCustomDiagID(Level Level, StringRef Message) {
0294     return getCustomDiagID([&]() -> CustomDiagDesc {
0295       switch (Level) {
0296       case DiagnosticIDs::Level::Ignored:
0297         return {diag::Severity::Ignored, std::string(Message), CLASS_WARNING,
0298                 /*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
0299       case DiagnosticIDs::Level::Note:
0300         return {diag::Severity::Fatal, std::string(Message), CLASS_NOTE,
0301                 /*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
0302       case DiagnosticIDs::Level::Remark:
0303         return {diag::Severity::Remark, std::string(Message), CLASS_REMARK,
0304                 /*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
0305       case DiagnosticIDs::Level::Warning:
0306         return {diag::Severity::Warning, std::string(Message), CLASS_WARNING,
0307                 /*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
0308       case DiagnosticIDs::Level::Error:
0309         return {diag::Severity::Error, std::string(Message), CLASS_ERROR,
0310                 /*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
0311       case DiagnosticIDs::Level::Fatal:
0312         return {diag::Severity::Fatal, std::string(Message), CLASS_ERROR,
0313                 /*ShowInSystemHeader*/ true, /*ShowInSystemMacro=*/true};
0314       }
0315       llvm_unreachable("Fully covered switch above!");
0316     }());
0317   }
0318 
0319   //===--------------------------------------------------------------------===//
0320   // Diagnostic classification and reporting interfaces.
0321   //
0322 
0323   /// Given a diagnostic ID, return a description of the issue.
0324   StringRef getDescription(unsigned DiagID) const;
0325 
0326   /// Return true if the unmapped diagnostic levelof the specified
0327   /// diagnostic ID is a Warning or Extension.
0328   ///
0329   /// This is not legal to call on NOTEs.
0330   bool isWarningOrExtension(unsigned DiagID) const;
0331 
0332   /// Return true if the specified diagnostic is mapped to errors by
0333   /// default.
0334   bool isDefaultMappingAsError(unsigned DiagID) const;
0335 
0336   /// Get the default mapping for this diagnostic.
0337   DiagnosticMapping getDefaultMapping(unsigned DiagID) const;
0338 
0339   void initCustomDiagMapping(DiagnosticMapping &, unsigned DiagID);
0340 
0341   /// Determine whether the given diagnostic ID is a Note.
0342   bool isNote(unsigned DiagID) const;
0343 
0344   /// Determine whether the given diagnostic ID is for an
0345   /// extension of some sort.
0346   bool isExtensionDiag(unsigned DiagID) const {
0347     bool ignored;
0348     return isExtensionDiag(DiagID, ignored);
0349   }
0350 
0351   /// Determine whether the given diagnostic ID is for an
0352   /// extension of some sort, and whether it is enabled by default.
0353   ///
0354   /// This also returns EnabledByDefault, which is set to indicate whether the
0355   /// diagnostic is ignored by default (in which case -pedantic enables it) or
0356   /// treated as a warning/error by default.
0357   ///
0358   bool isExtensionDiag(unsigned DiagID, bool &EnabledByDefault) const;
0359 
0360   /// Given a group ID, returns the flag that toggles the group.
0361   /// For example, for Group::DeprecatedDeclarations, returns
0362   /// "deprecated-declarations".
0363   static StringRef getWarningOptionForGroup(diag::Group);
0364 
0365   /// Given a diagnostic group ID, return its documentation.
0366   static StringRef getWarningOptionDocumentation(diag::Group GroupID);
0367 
0368   void setGroupSeverity(StringRef Group, diag::Severity);
0369   void setGroupNoWarningsAsError(StringRef Group, bool);
0370 
0371   /// Given a group ID, returns the flag that toggles the group.
0372   /// For example, for "deprecated-declarations", returns
0373   /// Group::DeprecatedDeclarations.
0374   static std::optional<diag::Group> getGroupForWarningOption(StringRef);
0375 
0376   /// Return the lowest-level group that contains the specified diagnostic.
0377   std::optional<diag::Group> getGroupForDiag(unsigned DiagID) const;
0378 
0379   /// Return the lowest-level warning option that enables the specified
0380   /// diagnostic.
0381   ///
0382   /// If there is no -Wfoo flag that controls the diagnostic, this returns null.
0383   StringRef getWarningOptionForDiag(unsigned DiagID);
0384 
0385   /// Return the category number that a specified \p DiagID belongs to,
0386   /// or 0 if no category.
0387   static unsigned getCategoryNumberForDiag(unsigned DiagID);
0388 
0389   /// Return the number of diagnostic categories.
0390   static unsigned getNumberOfCategories();
0391 
0392   /// Given a category ID, return the name of the category.
0393   static StringRef getCategoryNameFromID(unsigned CategoryID);
0394 
0395   /// Return true if a given diagnostic falls into an ARC diagnostic
0396   /// category.
0397   static bool isARCDiagnostic(unsigned DiagID);
0398 
0399   /// Return true if a given diagnostic is a codegen-time ABI check.
0400   static bool isCodegenABICheckDiagnostic(unsigned DiagID);
0401 
0402   /// Enumeration describing how the emission of a diagnostic should
0403   /// be treated when it occurs during C++ template argument deduction.
0404   enum SFINAEResponse {
0405     /// The diagnostic should not be reported, but it should cause
0406     /// template argument deduction to fail.
0407     ///
0408     /// The vast majority of errors that occur during template argument
0409     /// deduction fall into this category.
0410     SFINAE_SubstitutionFailure,
0411 
0412     /// The diagnostic should be suppressed entirely.
0413     ///
0414     /// Warnings generally fall into this category.
0415     SFINAE_Suppress,
0416 
0417     /// The diagnostic should be reported.
0418     ///
0419     /// The diagnostic should be reported. Various fatal errors (e.g.,
0420     /// template instantiation depth exceeded) fall into this category.
0421     SFINAE_Report,
0422 
0423     /// The diagnostic is an access-control diagnostic, which will be
0424     /// substitution failures in some contexts and reported in others.
0425     SFINAE_AccessControl
0426   };
0427 
0428   /// Determines whether the given built-in diagnostic ID is
0429   /// for an error that is suppressed if it occurs during C++ template
0430   /// argument deduction.
0431   ///
0432   /// When an error is suppressed due to SFINAE, the template argument
0433   /// deduction fails but no diagnostic is emitted. Certain classes of
0434   /// errors, such as those errors that involve C++ access control,
0435   /// are not SFINAE errors.
0436   static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
0437 
0438   /// Whether the diagnostic message can be deferred.
0439   ///
0440   /// For single source offloading languages, a diagnostic message occurred
0441   /// in a device host function may be deferred until the function is sure
0442   /// to be emitted.
0443   static bool isDeferrable(unsigned DiagID);
0444 
0445   /// Get the string of all diagnostic flags.
0446   ///
0447   /// \returns A list of all diagnostics flags as they would be written in a
0448   /// command line invocation including their `no-` variants. For example:
0449   /// `{"-Wempty-body", "-Wno-empty-body", ...}`
0450   static std::vector<std::string> getDiagnosticFlags();
0451 
0452   /// Get the set of all diagnostic IDs in the group with the given name.
0453   ///
0454   /// \param[out] Diags - On return, the diagnostics in the group.
0455   /// \returns \c true if the given group is unknown, \c false otherwise.
0456   bool getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
0457                              SmallVectorImpl<diag::kind> &Diags) const;
0458 
0459   /// Get the set of all diagnostic IDs.
0460   static void getAllDiagnostics(diag::Flavor Flavor,
0461                                 std::vector<diag::kind> &Diags);
0462 
0463   /// Get the diagnostic option with the closest edit distance to the
0464   /// given group name.
0465   static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group);
0466 
0467 private:
0468   /// Classify the specified diagnostic ID into a Level, consumable by
0469   /// the DiagnosticClient.
0470   ///
0471   /// The classification is based on the way the client configured the
0472   /// DiagnosticsEngine object.
0473   ///
0474   /// \param Loc The source location for which we are interested in finding out
0475   /// the diagnostic state. Can be null in order to query the latest state.
0476   DiagnosticIDs::Level
0477   getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
0478                      const DiagnosticsEngine &Diag) const LLVM_READONLY;
0479 
0480   diag::Severity
0481   getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
0482                         const DiagnosticsEngine &Diag) const LLVM_READONLY;
0483 
0484   Class getDiagClass(unsigned DiagID) const;
0485 
0486   /// Used to report a diagnostic that is finally fully formed.
0487   ///
0488   /// \returns \c true if the diagnostic was emitted, \c false if it was
0489   /// suppressed.
0490   bool ProcessDiag(DiagnosticsEngine &Diag,
0491                    const DiagnosticBuilder &DiagBuilder) const;
0492 
0493   /// Used to emit a diagnostic that is finally fully formed,
0494   /// ignoring suppression.
0495   void EmitDiag(DiagnosticsEngine &Diag, const DiagnosticBuilder &DiagBuilder,
0496                 Level DiagLevel) const;
0497 
0498   /// Whether the diagnostic may leave the AST in a state where some
0499   /// invariants can break.
0500   bool isUnrecoverable(unsigned DiagID) const;
0501 
0502   friend class DiagnosticsEngine;
0503 };
0504 
0505 }  // end namespace clang
0506 
0507 #endif