Skip to content

Commit 032adbf

Browse files
committed
[cas] Fix caching of diagnostics using getCustomDiagID
Custom diagnostics need to be serialized so that they can be registered with the diagnostic engine during replay. If any custom diagnostics are emitted, we capture all the known custom diagnostics. While this could theoretically be wasteful, in practice custom diagnostics are created only when they will be emitted. Note: this also fixes clang/test/CAS/analyze-action.c. (cherry picked from commit 61d414a) (cherry picked from commit ee2a43d)
1 parent 712a030 commit 032adbf

File tree

5 files changed

+147
-0
lines changed

5 files changed

+147
-0
lines changed

clang/include/clang/Basic/Diagnostic.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,18 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
880880
StringRef(FormatString, N - 1));
881881
}
882882

883+
unsigned getCustomDiagID(DiagnosticIDs::CustomDiagDesc Desc) {
884+
return Diags->getCustomDiagID(std::move(Desc));
885+
}
886+
887+
std::optional<unsigned> getMaxCustomDiagID() const {
888+
return Diags->getMaxCustomDiagID();
889+
}
890+
const DiagnosticIDs::CustomDiagDesc &
891+
getCustomDiagDesc(unsigned DiagID) const {
892+
return Diags->getCustomDiagDesc(DiagID);
893+
}
894+
883895
/// Converts a diagnostic argument (as an intptr_t) into the string
884896
/// that represents it.
885897
void ConvertArgToString(ArgumentKind Kind, intptr_t Val,

clang/include/clang/Basic/DiagnosticIDs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
245245
Class GetClass() const { return static_cast<Class>(DiagClass); }
246246
std::string_view GetDescription() const { return Description; }
247247
bool ShouldShowInSystemHeader() const { return ShowInSystemHeader; }
248+
bool ShouldShowInSystemMacro() const { return ShowInSystemMacro; }
248249

249250
friend bool operator==(const CustomDiagDesc &lhs,
250251
const CustomDiagDesc &rhs) {
@@ -318,6 +319,9 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
318319
}());
319320
}
320321

322+
std::optional<unsigned> getMaxCustomDiagID() const;
323+
const CustomDiagDesc &getCustomDiagDesc(unsigned DiagID) const;
324+
321325
//===--------------------------------------------------------------------===//
322326
// Diagnostic classification and reporting interfaces.
323327
//

clang/lib/Basic/DiagnosticIDs.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ class CustomDiagInfo {
315315
return Diags->second;
316316
return {};
317317
}
318+
319+
unsigned getMaxCustomDiagID() const {
320+
return DIAG_UPPER_LIMIT + DiagInfo.size();
321+
}
318322
};
319323

320324
} // namespace diag
@@ -433,6 +437,18 @@ unsigned DiagnosticIDs::getCustomDiagID(CustomDiagDesc Diag) {
433437
return CustomDiagInfo->getOrCreateDiagID(Diag);
434438
}
435439

440+
std::optional<unsigned> DiagnosticIDs::getMaxCustomDiagID() const {
441+
if (CustomDiagInfo)
442+
return CustomDiagInfo->getMaxCustomDiagID();
443+
return std::nullopt;
444+
}
445+
446+
const DiagnosticIDs::CustomDiagDesc &
447+
DiagnosticIDs::getCustomDiagDesc(unsigned DiagID) const {
448+
assert(IsCustomDiag(DiagID));
449+
return CustomDiagInfo->getDescription(DiagID);
450+
}
451+
436452
bool DiagnosticIDs::isWarningOrExtension(unsigned DiagID) const {
437453
return DiagID < diag::DIAG_UPPER_LIMIT
438454
? getDiagClass(DiagID) != CLASS_ERROR

clang/lib/Frontend/CachedDiagnostics.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
111132
struct 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+
459526
template <> 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)
545613
LLVM_YAML_IS_SEQUENCE_VECTOR(cached_diagnostics::Diagnostic)
546614
LLVM_YAML_IS_SEQUENCE_VECTOR(cached_diagnostics::Range)
547615
LLVM_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

549639
std::optional<std::string>
550640
CachedDiagnosticSerializer::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

clang/test/CAS/custom-diags.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
3+
// RUN: not %clang_cc1 -triple arm64-apple-macosx12 -fsyntax-only %s 2> %t/diags-orig
4+
5+
// RUN: %clang -cc1depscan -fdepscan=inline -fdepscan-include-tree -o %t/t.rsp -cc1-args \
6+
// RUN: -cc1 -triple arm64-apple-macosx12 -fcas-path %t/cas -fsyntax-only %s
7+
// RUN: not %clang @%t/t.rsp 2> %t/diags-cached
8+
9+
// RUN: diff -u %t/diags-orig %t/diags-cached
10+
11+
// RUN: FileCheck %s -input-file %t/diags-cached
12+
13+
const char s8[] = @encode(__SVInt8_t);
14+
// CHECK: cannot yet @encode type __SVInt8_t

0 commit comments

Comments
 (0)