@@ -108,15 +108,38 @@ struct Diagnostic {
108108 std::vector<FixItHint> FixIts;
109109};
110110
111+ struct CustomDiagDesc {
112+ diag::Severity DefaultSeverity;
113+ DiagnosticIDs::Class DiagClass;
114+ bool ShowInSystemHeader;
115+ bool ShowInSystemMacro;
116+ std::string Description;
117+ std::optional<diag::Group> Group;
118+ CustomDiagDesc () = default ;
119+ CustomDiagDesc (const DiagnosticIDs::CustomDiagDesc &Desc)
120+ : DefaultSeverity(Desc.GetDefaultSeverity()), DiagClass(Desc.GetClass()),
121+ ShowInSystemHeader (Desc.ShouldShowInSystemHeader()),
122+ ShowInSystemMacro(Desc.ShouldShowInSystemMacro()),
123+ Description(Desc.GetDescription()), Group(Desc.GetGroup()) {}
124+
125+ DiagnosticIDs::CustomDiagDesc getDesc () const {
126+ return DiagnosticIDs::CustomDiagDesc (DefaultSeverity, Description,
127+ DiagClass, ShowInSystemHeader,
128+ ShowInSystemMacro, Group);
129+ }
130+ };
131+
111132struct Diagnostics {
112133 std::vector<SLocEntry> SLocEntries;
113134 std::vector<Diagnostic> Diags;
135+ std::vector<CustomDiagDesc> CustomDiags;
114136
115137 size_t getNumDiags () const { return Diags.size (); }
116138
117139 void clear () {
118140 SLocEntries.clear ();
119141 Diags.clear ();
142+ CustomDiags.clear ();
120143 }
121144};
122145
@@ -198,6 +221,10 @@ struct CachedDiagnosticSerializer {
198221 // / produced it.
199222 std::optional<std::string> serializeEmittedDiagnostics ();
200223 Error deserializeCachedDiagnostics (StringRef Buffer);
224+
225+ // / Capture any custom diagnostics registerd by \p Diags so that they can be
226+ // / later serialized.
227+ void captureCustomDiags (const DiagnosticsEngine &Diags);
201228};
202229
203230} // anonymous namespace
@@ -456,6 +483,46 @@ template <> struct MappingTraits<cached_diagnostics::SLocEntry> {
456483 }
457484};
458485
486+ template <> struct ScalarEnumerationTraits <diag::Severity> {
487+ static void enumeration (IO &io, diag::Severity &value) {
488+ io.enumCase (value, " ignored" , diag::Severity::Ignored);
489+ io.enumCase (value, " remark" , diag::Severity::Remark);
490+ io.enumCase (value, " warning" , diag::Severity::Warning);
491+ io.enumCase (value, " error" , diag::Severity::Error);
492+ io.enumCase (value, " fatal" , diag::Severity::Fatal);
493+ }
494+ };
495+ template <> struct ScalarEnumerationTraits <DiagnosticIDs::Class> {
496+ static void enumeration (IO &io, DiagnosticIDs::Class &value) {
497+ io.enumCase (value, " invalid" , DiagnosticIDs::CLASS_INVALID);
498+ io.enumCase (value, " note" , DiagnosticIDs::CLASS_NOTE);
499+ io.enumCase (value, " remark" , DiagnosticIDs::CLASS_REMARK);
500+ io.enumCase (value, " warning" , DiagnosticIDs::CLASS_WARNING);
501+ io.enumCase (value, " extension" , DiagnosticIDs::CLASS_EXTENSION);
502+ io.enumCase (value, " error" , DiagnosticIDs::CLASS_ERROR);
503+ }
504+ };
505+ template <> struct ScalarEnumerationTraits <diag::Group> {
506+ static void enumeration (IO &io, diag::Group &value) {
507+ #define DIAG_ENTRY (GroupName, FlagNameOffset, Members, SubGroups, Docs ) \
508+ io.enumCase (value, #GroupName, diag::Group::GroupName);
509+ #include " clang/Basic/DiagnosticGroups.inc"
510+ #undef CATEGORY
511+ #undef DIAG_ENTRY
512+ }
513+ };
514+
515+ template <> struct MappingTraits <cached_diagnostics::CustomDiagDesc> {
516+ static void mapping (IO &io, cached_diagnostics::CustomDiagDesc &DiagDesc) {
517+ io.mapRequired (" severity" , DiagDesc.DefaultSeverity );
518+ io.mapRequired (" class" , DiagDesc.DiagClass );
519+ io.mapRequired (" show_in_system_header" , DiagDesc.ShowInSystemHeader );
520+ io.mapRequired (" show_in_system_macro" , DiagDesc.ShowInSystemMacro );
521+ io.mapRequired (" description" , DiagDesc.Description );
522+ io.mapOptional (" group" , DiagDesc.Group );
523+ }
524+ };
525+
459526template <> struct MappingTraits <cached_diagnostics::SLocEntry::FileInfo> {
460527 static void mapping (IO &io, cached_diagnostics::SLocEntry::FileInfo &s) {
461528 io.mapRequired (" filename" , s.Filename );
@@ -537,6 +604,7 @@ template <> struct MappingTraits<cached_diagnostics::Diagnostics> {
537604 static void mapping (IO &io, cached_diagnostics::Diagnostics &s) {
538605 io.mapRequired (" sloc_entries" , s.SLocEntries );
539606 io.mapRequired (" diagnostics" , s.Diags );
607+ io.mapRequired (" custom_diagnostics" , s.CustomDiags );
540608 }
541609};
542610} // namespace llvm::yaml
@@ -545,6 +613,28 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(cached_diagnostics::SLocEntry)
545613LLVM_YAML_IS_SEQUENCE_VECTOR(cached_diagnostics::Diagnostic)
546614LLVM_YAML_IS_SEQUENCE_VECTOR(cached_diagnostics::Range)
547615LLVM_YAML_IS_SEQUENCE_VECTOR(cached_diagnostics::FixItHint)
616+ LLVM_YAML_IS_SEQUENCE_VECTOR(cached_diagnostics::CustomDiagDesc)
617+
618+ void CachedDiagnosticSerializer::captureCustomDiags(
619+ const DiagnosticsEngine &Diags) {
620+ auto MaxCustomDiagID = Diags.getMaxCustomDiagID ();
621+ if (!MaxCustomDiagID)
622+ return ;
623+
624+ // Capture any custom diagnostics we have not already seen.
625+ unsigned FirstUnknownDiag =
626+ diag::DIAG_UPPER_LIMIT + CachedDiags.CustomDiags .size ();
627+ for (unsigned DiagID = FirstUnknownDiag; DiagID < *MaxCustomDiagID;
628+ ++DiagID) {
629+ auto Desc = Diags.getCustomDiagDesc (DiagID);
630+ CachedDiags.CustomDiags .push_back (Desc);
631+
632+ // Forward the custom diagnostic to the Serializer's diagnostic engine.
633+ auto SerializerDiagID = DiagEngine.getCustomDiagID (Desc);
634+ assert (SerializerDiagID == DiagID && " mismatched custom diags" );
635+ (void )SerializerDiagID;
636+ }
637+ }
548638
549639std::optional<std::string>
550640CachedDiagnosticSerializer::serializeEmittedDiagnostics () {
@@ -613,6 +703,13 @@ Error CachedDiagnosticSerializer::deserializeCachedDiagnostics(
613703 if (YIn.error ())
614704 return createStringError (YIn.error (),
615705 " failed deserializing cached diagnostics" );
706+
707+ assert (DiagEngine.getMaxCustomDiagID () == std::nullopt &&
708+ " existing custom diagnostics will conflict" );
709+ for (const auto &CustomDiag : CachedDiags.CustomDiags ) {
710+ (void )DiagEngine.getCustomDiagID (CustomDiag.getDesc ());
711+ }
712+
616713 return Error::success ();
617714}
618715
@@ -661,6 +758,10 @@ struct CachingDiagnosticsProcessor::DiagnosticsConsumer
661758 if (shouldCacheDiagnostic (Level, Info)) {
662759 unsigned DiagIdx = Serializer.addDiag (StoredDiagnostic (Level, Info));
663760 StoredDiagnostic NewDiag = Serializer.getDiag (DiagIdx);
761+
762+ if (DiagnosticIDs::IsCustomDiag (NewDiag.getID ()))
763+ Serializer.captureCustomDiags (*Info.getDiags ());
764+
664765 // Pass the converted diagnostic to the original consumer. We do this
665766 // because:
666767 // 1. It ensures that the rendered diagnostics will use the same
0 commit comments