From 815f466da0e72e6b0939c182aa1535b06c6df734 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 3 Feb 2026 22:33:13 +0100 Subject: [PATCH 1/7] Convert to inline diagnostics in `rustc_pattern_analysis` --- Cargo.lock | 2 - compiler/rustc_driver_impl/Cargo.toml | 1 - compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_pattern_analysis/Cargo.toml | 2 - compiler/rustc_pattern_analysis/messages.ftl | 31 ---------- compiler/rustc_pattern_analysis/src/errors.rs | 61 +++++++++++++------ compiler/rustc_pattern_analysis/src/lib.rs | 3 - 7 files changed, 41 insertions(+), 60 deletions(-) delete mode 100644 compiler/rustc_pattern_analysis/messages.ftl diff --git a/Cargo.lock b/Cargo.lock index 91fce715c8cd1..38146bae4bbe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3808,7 +3808,6 @@ dependencies = [ "rustc_monomorphize", "rustc_parse", "rustc_passes", - "rustc_pattern_analysis", "rustc_privacy", "rustc_public", "rustc_query_system", @@ -4477,7 +4476,6 @@ dependencies = [ "rustc_arena", "rustc_data_structures", "rustc_errors", - "rustc_fluent_macro", "rustc_hir", "rustc_index", "rustc_macros", diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index d97c552b412b5..35c475e1e5665 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -40,7 +40,6 @@ rustc_mir_transform = { path = "../rustc_mir_transform" } rustc_monomorphize = { path = "../rustc_monomorphize" } rustc_parse = { path = "../rustc_parse" } rustc_passes = { path = "../rustc_passes" } -rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } rustc_privacy = { path = "../rustc_privacy" } rustc_public = { path = "../rustc_public", features = ["rustc_internal"] } rustc_query_system = { path = "../rustc_query_system" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b163ae2068a66..5215866665330 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -137,7 +137,6 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_monomorphize::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE, rustc_passes::DEFAULT_LOCALE_RESOURCE, - rustc_pattern_analysis::DEFAULT_LOCALE_RESOURCE, rustc_privacy::DEFAULT_LOCALE_RESOURCE, rustc_query_system::DEFAULT_LOCALE_RESOURCE, rustc_resolve::DEFAULT_LOCALE_RESOURCE, diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index a59f7bbeb9e5e..a644c6a7c01a2 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -11,7 +11,6 @@ rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_errors = { path = "../rustc_errors", optional = true } -rustc_fluent_macro = { path = "../rustc_fluent_macro", optional = true } rustc_hir = { path = "../rustc_hir", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } @@ -36,7 +35,6 @@ rustc = [ "dep:rustc_arena", "dep:rustc_data_structures", "dep:rustc_errors", - "dep:rustc_fluent_macro", "dep:rustc_hir", "dep:rustc_macros", "dep:rustc_middle", diff --git a/compiler/rustc_pattern_analysis/messages.ftl b/compiler/rustc_pattern_analysis/messages.ftl deleted file mode 100644 index d3a3107f8e898..0000000000000 --- a/compiler/rustc_pattern_analysis/messages.ftl +++ /dev/null @@ -1,31 +0,0 @@ -pattern_analysis_excluside_range_missing_gap = multiple ranges are one apart - .label = this range doesn't match `{$gap}` because `..` is an exclusive range - .suggestion = use an inclusive range instead - -pattern_analysis_excluside_range_missing_max = exclusive range missing `{$max}` - .label = this range doesn't match `{$max}` because `..` is an exclusive range - .suggestion = use an inclusive range instead - -pattern_analysis_mixed_deref_pattern_constructors = mix of deref patterns and normal constructors - .deref_pattern_label = matches on the result of dereferencing `{$smart_pointer_ty}` - .normal_constructor_label = matches directly on `{$smart_pointer_ty}` - -pattern_analysis_non_exhaustive_omitted_pattern = some variants are not matched explicitly - .help = ensure that all variants are matched explicitly by adding the suggested match arms - .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found - -pattern_analysis_non_exhaustive_omitted_pattern_lint_on_arm = the lint level must be set on the whole match - .help = it no longer has any effect to set the lint level on an individual match arm - .label = remove this attribute - .suggestion = set the lint level on the whole match - -pattern_analysis_overlapping_range_endpoints = multiple patterns overlap on their endpoints - .label = ... with this range - .note = you likely meant to write mutually exclusive ranges - -pattern_analysis_uncovered = {$count -> - [1] pattern `{$witness_1}` - [2] patterns `{$witness_1}` and `{$witness_2}` - [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}` - *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more - } not covered diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 156ba9737673e..64d4ff4220430 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -6,7 +6,14 @@ use rustc_span::Span; use crate::rustc::{RustcPatCtxt, WitnessPat}; #[derive(Subdiagnostic)] -#[label(pattern_analysis_uncovered)] +#[label( + "{$count -> + [1] pattern `{$witness_1}` + [2] patterns `{$witness_1}` and `{$witness_2}` + [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}` + *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more + } not covered" +)] pub struct Uncovered { #[primary_span] span: Span, @@ -40,10 +47,10 @@ impl Uncovered { } #[derive(LintDiagnostic)] -#[diag(pattern_analysis_overlapping_range_endpoints)] -#[note] +#[diag("multiple patterns overlap on their endpoints")] +#[note("you likely meant to write mutually exclusive ranges")] pub struct OverlappingRangeEndpoints { - #[label] + #[label("... with this range")] pub range: Span, #[subdiagnostic] pub overlap: Vec, @@ -66,10 +73,14 @@ impl Subdiagnostic for Overlap { } #[derive(LintDiagnostic)] -#[diag(pattern_analysis_excluside_range_missing_max)] +#[diag("exclusive range missing `{$max}`")] pub struct ExclusiveRangeMissingMax { - #[label] - #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] + #[label("this range doesn't match `{$max}` because `..` is an exclusive range")] + #[suggestion( + "use an inclusive range instead", + code = "{suggestion}", + applicability = "maybe-incorrect" + )] /// This is an exclusive range that looks like `lo..max` (i.e. doesn't match `max`). pub first_range: Span, /// Suggest `lo..=max` instead. @@ -78,10 +89,14 @@ pub struct ExclusiveRangeMissingMax { } #[derive(LintDiagnostic)] -#[diag(pattern_analysis_excluside_range_missing_gap)] +#[diag("multiple ranges are one apart")] pub struct ExclusiveRangeMissingGap { - #[label] - #[suggestion(code = "{suggestion}", applicability = "maybe-incorrect")] + #[label("this range doesn't match `{$gap}` because `..` is an exclusive range")] + #[suggestion( + "use an inclusive range instead", + code = "{suggestion}", + applicability = "maybe-incorrect" + )] /// This is an exclusive range that looks like `lo..gap` (i.e. doesn't match `gap`). pub first_range: Span, pub gap: String, // a printed pattern @@ -113,9 +128,11 @@ impl Subdiagnostic for GappedRange { } #[derive(LintDiagnostic)] -#[diag(pattern_analysis_non_exhaustive_omitted_pattern)] -#[help] -#[note] +#[diag("some variants are not matched explicitly")] +#[help("ensure that all variants are matched explicitly by adding the suggested match arms")] +#[note( + "the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found" +)] pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { pub scrut_ty: Ty<'tcx>, #[subdiagnostic] @@ -123,25 +140,29 @@ pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { } #[derive(LintDiagnostic)] -#[diag(pattern_analysis_non_exhaustive_omitted_pattern_lint_on_arm)] -#[help] +#[diag("the lint level must be set on the whole match")] +#[help("it no longer has any effect to set the lint level on an individual match arm")] pub(crate) struct NonExhaustiveOmittedPatternLintOnArm { - #[label] + #[label("remove this attribute")] pub lint_span: Span, - #[suggestion(code = "#[{lint_level}({lint_name})]\n", applicability = "maybe-incorrect")] + #[suggestion( + "set the lint level on the whole match", + code = "#[{lint_level}({lint_name})]\n", + applicability = "maybe-incorrect" + )] pub suggest_lint_on_match: Option, pub lint_level: &'static str, pub lint_name: &'static str, } #[derive(Diagnostic)] -#[diag(pattern_analysis_mixed_deref_pattern_constructors)] +#[diag("mix of deref patterns and normal constructors")] pub(crate) struct MixedDerefPatternConstructors<'tcx> { #[primary_span] pub spans: Vec, pub smart_pointer_ty: Ty<'tcx>, - #[label(pattern_analysis_deref_pattern_label)] + #[label("matches on the result of dereferencing `{$smart_pointer_ty}`")] pub deref_pattern_label: Span, - #[label(pattern_analysis_normal_constructor_label)] + #[label("matches directly on `{$smart_pointer_ty}`")] pub normal_constructor_label: Span, } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 2652840863776..9ffc237c63290 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -19,9 +19,6 @@ pub mod pat_column; pub mod rustc; pub mod usefulness; -#[cfg(feature = "rustc")] -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - use std::fmt; pub use rustc_index::{Idx, IndexVec}; // re-exported to avoid rustc_index version issues From d457ffd4f4589dfdd1f8fd2ef1c3d784018cf127 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 3 Feb 2026 22:44:03 +0100 Subject: [PATCH 2/7] Convert to inline diagnostics in `rustc_monomorphize` --- Cargo.lock | 2 - compiler/rustc_driver_impl/Cargo.toml | 1 - compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_monomorphize/Cargo.toml | 1 - compiler/rustc_monomorphize/messages.ftl | 82 ---------------- compiler/rustc_monomorphize/src/errors.rs | 109 ++++++++++++++++------ compiler/rustc_monomorphize/src/lib.rs | 2 - 7 files changed, 82 insertions(+), 116 deletions(-) delete mode 100644 compiler/rustc_monomorphize/messages.ftl diff --git a/Cargo.lock b/Cargo.lock index 91fce715c8cd1..b7dd59d857fdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3805,7 +3805,6 @@ dependencies = [ "rustc_mir_build", "rustc_mir_dataflow", "rustc_mir_transform", - "rustc_monomorphize", "rustc_parse", "rustc_passes", "rustc_pattern_analysis", @@ -4384,7 +4383,6 @@ dependencies = [ "rustc_abi", "rustc_data_structures", "rustc_errors", - "rustc_fluent_macro", "rustc_hir", "rustc_index", "rustc_macros", diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index d97c552b412b5..28972d1c35ecd 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -37,7 +37,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_mir_build = { path = "../rustc_mir_build" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } rustc_mir_transform = { path = "../rustc_mir_transform" } -rustc_monomorphize = { path = "../rustc_monomorphize" } rustc_parse = { path = "../rustc_parse" } rustc_passes = { path = "../rustc_passes" } rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b163ae2068a66..80724c6a24f5c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -134,7 +134,6 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_mir_build::DEFAULT_LOCALE_RESOURCE, rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE, rustc_mir_transform::DEFAULT_LOCALE_RESOURCE, - rustc_monomorphize::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE, rustc_passes::DEFAULT_LOCALE_RESOURCE, rustc_pattern_analysis::DEFAULT_LOCALE_RESOURCE, diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 0829d52283abf..552c092ef7c46 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl deleted file mode 100644 index 9c791208c0935..0000000000000 --- a/compiler/rustc_monomorphize/messages.ftl +++ /dev/null @@ -1,82 +0,0 @@ -monomorphize_abi_error_disabled_vector_type = - this function {$is_call -> - [true] call - *[false] definition - } uses {$is_scalable -> - [true] scalable - *[false] SIMD - } vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> - [true] {" "}in the caller - *[false] {""} - } - .label = function {$is_call -> - [true] called - *[false] defined - } here - .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) - -monomorphize_abi_error_unsupported_unsized_parameter = - this function {$is_call -> - [true] call - *[false] definition - } uses unsized type `{$ty}` which is not supported with the chosen ABI - .label = function {$is_call -> - [true] called - *[false] defined - } here - .help = only rustic ABIs support unsized parameters - -monomorphize_abi_error_unsupported_vector_type = - this function {$is_call -> - [true] call - *[false] definition - } uses SIMD vector type `{$ty}` which is not currently supported with the chosen ABI - .label = function {$is_call -> - [true] called - *[false] defined - } here - -monomorphize_abi_required_target_feature = - this function {$is_call -> - [true] call - *[false] definition - } uses ABI "{$abi}" which requires the `{$required_feature}` target feature, which is not enabled{$is_call -> - [true] {" "}in the caller - *[false] {""} - } - .label = function {$is_call -> - [true] called - *[false] defined - } here - .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) - -monomorphize_couldnt_dump_mono_stats = - unexpected error occurred while dumping monomorphization stats: {$error} - -monomorphize_encountered_error_while_instantiating = - the above error was encountered while instantiating `{$kind} {$instance}` - -monomorphize_encountered_error_while_instantiating_global_asm = - the above error was encountered while instantiating `global_asm` - -monomorphize_large_assignments = - moving {$size} bytes - .label = value moved from here - .note = the current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]` - -monomorphize_no_optimized_mir = - missing optimized MIR for `{$instance}` in the crate `{$crate_name}` - .note = missing optimized MIR for this item (was the crate `{$crate_name}` compiled with `--emit=metadata`?) - -monomorphize_recursion_limit = - reached the recursion limit while instantiating `{$instance}` - .note = `{$def_path_str}` defined here - -monomorphize_start_not_found = using `fn main` requires the standard library - .help = use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]` - -monomorphize_static_initializer_cyclic = static initializer forms a cycle involving `{$head}` - .label = part of this cycle - .note = cyclic static initializers are not supported for target `{$target}` - -monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 723649f22117e..d045ae0b92cba 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -3,37 +3,41 @@ use rustc_middle::ty::{Instance, Ty}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] -#[diag(monomorphize_recursion_limit)] +#[diag("reached the recursion limit while instantiating `{$instance}`")] pub(crate) struct RecursionLimit<'tcx> { #[primary_span] pub span: Span, pub instance: Instance<'tcx>, - #[note] + #[note("`{$def_path_str}` defined here")] pub def_span: Span, pub def_path_str: String, } #[derive(Diagnostic)] -#[diag(monomorphize_no_optimized_mir)] +#[diag("missing optimized MIR for `{$instance}` in the crate `{$crate_name}`")] pub(crate) struct NoOptimizedMir { - #[note] + #[note( + "missing optimized MIR for this item (was the crate `{$crate_name}` compiled with `--emit=metadata`?)" + )] pub span: Span, pub crate_name: Symbol, pub instance: String, } #[derive(LintDiagnostic)] -#[diag(monomorphize_large_assignments)] -#[note] +#[diag("moving {$size} bytes")] +#[note( + "the current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = \"...\"]`" +)] pub(crate) struct LargeAssignmentsLint { - #[label] + #[label("value moved from here")] pub span: Span, pub size: u64, pub limit: u64, } #[derive(Diagnostic)] -#[diag(monomorphize_symbol_already_defined)] +#[diag("symbol `{$symbol}` is already defined")] pub(crate) struct SymbolAlreadyDefined { #[primary_span] pub span: Option, @@ -41,13 +45,13 @@ pub(crate) struct SymbolAlreadyDefined { } #[derive(Diagnostic)] -#[diag(monomorphize_couldnt_dump_mono_stats)] +#[diag("unexpected error occurred while dumping monomorphization stats: {$error}")] pub(crate) struct CouldntDumpMonoStats { pub error: String, } #[derive(Diagnostic)] -#[diag(monomorphize_encountered_error_while_instantiating)] +#[diag("the above error was encountered while instantiating `{$kind} {$instance}`")] pub(crate) struct EncounteredErrorWhileInstantiating<'tcx> { #[primary_span] pub span: Span, @@ -56,23 +60,41 @@ pub(crate) struct EncounteredErrorWhileInstantiating<'tcx> { } #[derive(Diagnostic)] -#[diag(monomorphize_encountered_error_while_instantiating_global_asm)] +#[diag("the above error was encountered while instantiating `global_asm`")] pub(crate) struct EncounteredErrorWhileInstantiatingGlobalAsm { #[primary_span] pub span: Span, } #[derive(Diagnostic)] -#[diag(monomorphize_start_not_found)] -#[help] +#[diag("using `fn main` requires the standard library")] +#[help( + "use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]`" +)] pub(crate) struct StartNotFound; #[derive(Diagnostic)] -#[diag(monomorphize_abi_error_disabled_vector_type)] -#[help] +#[diag("this function {$is_call -> + [true] call + *[false] definition +} uses {$is_scalable -> + [true] scalable + *[false] SIMD +} vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> + [true] {\" \"}in the caller + *[false] {\"\"} +}")] +#[help( + "consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable=\"{$required_feature}\")]`)" +)] pub(crate) struct AbiErrorDisabledVectorType<'a> { #[primary_span] - #[label] + #[label( + "function {$is_call -> + [true] called + *[false] defined + } here" + )] pub span: Span, pub required_feature: &'a str, pub ty: Ty<'a>, @@ -83,11 +105,21 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> { } #[derive(Diagnostic)] -#[diag(monomorphize_abi_error_unsupported_unsized_parameter)] -#[help] +#[diag( + "this function {$is_call -> + [true] call + *[false] definition + } uses unsized type `{$ty}` which is not supported with the chosen ABI" +)] +#[help("only rustic ABIs support unsized parameters")] pub(crate) struct AbiErrorUnsupportedUnsizedParameter<'a> { #[primary_span] - #[label] + #[label( + "function {$is_call -> + [true] called + *[false] defined + } here" + )] pub span: Span, pub ty: Ty<'a>, /// Whether this is a problem at a call site or at a declaration. @@ -95,10 +127,20 @@ pub(crate) struct AbiErrorUnsupportedUnsizedParameter<'a> { } #[derive(Diagnostic)] -#[diag(monomorphize_abi_error_unsupported_vector_type)] +#[diag( + "this function {$is_call -> + [true] call + *[false] definition + } uses SIMD vector type `{$ty}` which is not currently supported with the chosen ABI" +)] pub(crate) struct AbiErrorUnsupportedVectorType<'a> { #[primary_span] - #[label] + #[label( + "function {$is_call -> + [true] called + *[false] defined + } here" + )] pub span: Span, pub ty: Ty<'a>, /// Whether this is a problem at a call site or at a declaration. @@ -106,11 +148,24 @@ pub(crate) struct AbiErrorUnsupportedVectorType<'a> { } #[derive(Diagnostic)] -#[diag(monomorphize_abi_required_target_feature)] -#[help] +#[diag("this function {$is_call -> + [true] call + *[false] definition +} uses ABI \"{$abi}\" which requires the `{$required_feature}` target feature, which is not enabled{$is_call -> + [true] {\" \"}in the caller + *[false] {\"\"} +}")] +#[help( + "consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable=\"{$required_feature}\")]`)" +)] pub(crate) struct AbiRequiredTargetFeature<'a> { #[primary_span] - #[label] + #[label( + "function {$is_call -> +[true] called +*[false] defined +} here" + )] pub span: Span, pub required_feature: &'a str, pub abi: &'a str, @@ -119,12 +174,12 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { } #[derive(Diagnostic)] -#[diag(monomorphize_static_initializer_cyclic)] -#[note] +#[diag("static initializer forms a cycle involving `{$head}`")] +#[note("cyclic static initializers are not supported for target `{$target}`")] pub(crate) struct StaticInitializerCyclic<'a> { #[primary_span] pub span: Span, - #[label] + #[label("part of this cycle")] pub labels: Vec, pub head: &'a str, pub target: &'a str, diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 30f6934bb9372..51753563b67c9 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -20,8 +20,6 @@ mod mono_checks; mod partitioning; mod util; -rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - fn custom_coerce_unsize_info<'tcx>( tcx: TyCtxtAt<'tcx>, source_ty: Ty<'tcx>, From f5e4b290aa20b5db44d750ede49712cbf2048f74 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 2 Feb 2026 15:27:05 +1100 Subject: [PATCH 3/7] Move `rustc_query_system::values` module into `rustc_middle`. It's a tiny module with one trait and a default impl. It's not used in `rustc_query_system`; all uses and non-default impls are in `rustc_middle` and `rustc_query_impl`. This commit moves it into `rustc_middle`, which makes things simpler overall. --- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_middle/src/values.rs | 41 +++++++++++++++++------ compiler/rustc_query_impl/src/lib.rs | 2 +- compiler/rustc_query_system/src/lib.rs | 2 -- compiler/rustc_query_system/src/values.rs | 21 ------------ 5 files changed, 32 insertions(+), 36 deletions(-) delete mode 100644 compiler/rustc_query_system/src/values.rs diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5682c21e43533..198fa6eca7944 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -81,7 +81,7 @@ pub mod thir; pub mod traits; pub mod ty; pub mod util; -mod values; +pub mod values; #[macro_use] pub mod query; diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index fd08b5a972c68..0828758cc94ef 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -7,7 +7,6 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_query_system::Value; use rustc_query_system::query::{CycleError, report_cycle}; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span}; @@ -16,7 +15,27 @@ use crate::dep_graph::dep_kinds; use crate::query::plumbing::CyclePlaceholder; use crate::ty::{self, Representability, Ty, TyCtxt}; -impl<'tcx> Value> for Ty<'_> { +pub trait Value<'tcx>: Sized { + fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) + -> Self; +} + +impl<'tcx, T> Value<'tcx> for T { + default fn from_cycle_error( + tcx: TyCtxt<'tcx>, + cycle_error: &CycleError, + _guar: ErrorGuaranteed, + ) -> T { + tcx.sess.dcx().abort_if_errors(); + bug!( + "<{} as Value>::from_cycle_error called without errors: {:#?}", + std::any::type_name::(), + cycle_error.cycle, + ); + } +} + +impl<'tcx> Value<'tcx> for Ty<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. @@ -24,13 +43,13 @@ impl<'tcx> Value> for Ty<'_> { } } -impl<'tcx> Value> for Result>, CyclePlaceholder> { +impl<'tcx> Value<'tcx> for Result>, CyclePlaceholder> { fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self { Err(CyclePlaceholder(guar)) } } -impl<'tcx> Value> for ty::SymbolName<'_> { +impl<'tcx> Value<'tcx> for ty::SymbolName<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, _guar: ErrorGuaranteed) -> Self { // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. @@ -42,7 +61,7 @@ impl<'tcx> Value> for ty::SymbolName<'_> { } } -impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { +impl<'tcx> Value<'tcx> for ty::Binder<'_, ty::FnSig<'_>> { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, @@ -76,7 +95,7 @@ impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { } } -impl<'tcx> Value> for Representability { +impl<'tcx> Value<'tcx> for Representability { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, @@ -112,7 +131,7 @@ impl<'tcx> Value> for Representability { } } -impl<'tcx> Value> for ty::EarlyBinder<'_, Ty<'_>> { +impl<'tcx> Value<'tcx> for ty::EarlyBinder<'_, Ty<'_>> { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, @@ -122,7 +141,7 @@ impl<'tcx> Value> for ty::EarlyBinder<'_, Ty<'_>> { } } -impl<'tcx> Value> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> { +impl<'tcx> Value<'tcx> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, @@ -132,7 +151,7 @@ impl<'tcx> Value> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig< } } -impl<'tcx> Value> for &[ty::Variance] { +impl<'tcx> Value<'tcx> for &[ty::Variance] { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, @@ -180,7 +199,7 @@ fn search_for_cycle_permutation( otherwise() } -impl<'tcx, T> Value> for Result> { +impl<'tcx, T> Value<'tcx> for Result> { fn from_cycle_error( tcx: TyCtxt<'tcx>, cycle_error: &CycleError, @@ -273,7 +292,7 @@ impl<'tcx, T> Value> for Result> // item_and_field_ids should form a cycle where each field contains the // type in the next element in the list -pub fn recursive_type_error( +fn recursive_type_error( tcx: TyCtxt<'_>, mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>, representable_ids: &FxHashSet, diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index bd69c99a32dc0..7a77860af9c43 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -19,7 +19,7 @@ use rustc_middle::query::{ AsLocalKey, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, queries, }; use rustc_middle::ty::TyCtxt; -use rustc_query_system::Value; +use rustc_middle::values::Value; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index d1907a8c582d8..3175dbb54bea2 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -10,7 +10,5 @@ pub mod dep_graph; mod error; pub mod ich; pub mod query; -mod values; pub use error::{QueryOverflow, QueryOverflowNote}; -pub use values::Value; diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs deleted file mode 100644 index 133904f59af14..0000000000000 --- a/compiler/rustc_query_system/src/values.rs +++ /dev/null @@ -1,21 +0,0 @@ -use rustc_span::ErrorGuaranteed; - -use crate::dep_graph::DepContext; -use crate::query::CycleError; - -pub trait Value: Sized { - fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, guar: ErrorGuaranteed) -> Self; -} - -impl Value for T { - default fn from_cycle_error(tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed) -> T { - tcx.sess().dcx().abort_if_errors(); - // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's - // non-trivial to define it earlier. - panic!( - "<{} as Value>::from_cycle_error called without errors: {:#?}", - std::any::type_name::(), - cycle_error.cycle, - ); - } -} From 71ac7bbfd9282a4f9bfb1659ff035e92767c7cb8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 4 Feb 2026 10:38:28 +1100 Subject: [PATCH 4/7] Move `rustc_middle::values` module to `rustc_middle::query::values`. It's a better place for it, because it relates to queries. --- compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_middle/src/query/mod.rs | 1 + compiler/rustc_middle/src/{ => query}/values.rs | 0 compiler/rustc_query_impl/src/lib.rs | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename compiler/rustc_middle/src/{ => query}/values.rs (100%) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 198fa6eca7944..af97df47b94fc 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -81,7 +81,6 @@ pub mod thir; pub mod traits; pub mod ty; pub mod util; -pub mod values; #[macro_use] pub mod query; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c9291d89be8aa..9514080c8f327 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -149,6 +149,7 @@ mod keys; pub mod on_disk_cache; #[macro_use] pub mod plumbing; +pub mod values; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/query/values.rs similarity index 100% rename from compiler/rustc_middle/src/values.rs rename to compiler/rustc_middle/src/query/values.rs diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 7a77860af9c43..29986d4759e24 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -15,11 +15,11 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::{self, DepKind, DepKindVTable, DepNodeIndex}; use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; use rustc_middle::query::plumbing::{QuerySystem, QuerySystemFns, QueryVTable}; +use rustc_middle::query::values::Value; use rustc_middle::query::{ AsLocalKey, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, queries, }; use rustc_middle::ty::TyCtxt; -use rustc_middle::values::Value; use rustc_query_system::dep_graph::SerializedDepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ From 4874c4afd09c8900fd2e0ae42a9bc69b17abea66 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 2 Feb 2026 16:05:26 +1100 Subject: [PATCH 5/7] Move the `QueryOverflow` and `QueryOverflowNote` errors. They are defined in `rustc_query_system` but used in `rustc_query_impl`. This is very much *not* how things are supposed to be done; I suspect someone got lazy and took a shortcut at some point. This commit moves the errors into `rustc_query_impl`. This requires more lines of code to give `rustc_query_impl` an errors module, but it's worthwhile to do things in the normal way instead of a weird exceptional way. --- Cargo.lock | 2 ++ compiler/rustc_query_impl/Cargo.toml | 2 ++ compiler/rustc_query_impl/src/error.rs | 24 +++++++++++++++++++++++ compiler/rustc_query_impl/src/lib.rs | 2 ++ compiler/rustc_query_impl/src/plumbing.rs | 2 +- compiler/rustc_query_system/src/error.rs | 24 +---------------------- compiler/rustc_query_system/src/lib.rs | 2 -- 7 files changed, 32 insertions(+), 26 deletions(-) create mode 100644 compiler/rustc_query_impl/src/error.rs diff --git a/Cargo.lock b/Cargo.lock index 2be69cf0b23bf..c1b18fa7411a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4545,9 +4545,11 @@ version = "0.0.0" dependencies = [ "measureme", "rustc_data_structures", + "rustc_errors", "rustc_hashes", "rustc_hir", "rustc_index", + "rustc_macros", "rustc_middle", "rustc_query_system", "rustc_serialize", diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 257785b10c8bc..d611629671a0a 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -7,9 +7,11 @@ edition = "2024" # tidy-alphabetical-start measureme = "12.0.1" rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_query_impl/src/error.rs b/compiler/rustc_query_impl/src/error.rs new file mode 100644 index 0000000000000..b109172d8e495 --- /dev/null +++ b/compiler/rustc_query_impl/src/error.rs @@ -0,0 +1,24 @@ +use rustc_hir::limit::Limit; +use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(Diagnostic)] +#[help( + "consider increasing the recursion limit by adding a `#![recursion_limit = \"{$suggested_limit}\"]` attribute to your crate (`{$crate_name}`)" +)] +#[diag("queries overflow the depth limit!")] +pub(crate) struct QueryOverflow { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub note: QueryOverflowNote, + pub suggested_limit: Limit, + pub crate_name: Symbol, +} + +#[derive(Subdiagnostic)] +#[note("query depth increased by {$depth} when {$desc}")] +pub(crate) struct QueryOverflowNote { + pub desc: String, + pub depth: usize, +} diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 29986d4759e24..fde7b9a56a2d6 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -38,6 +38,8 @@ pub use crate::plumbing::{QueryCtxt, query_key_hash_verify_all}; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; +mod error; + #[derive(ConstParamTy)] // Allow this struct to be used for const-generic values. #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct QueryFlags { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index d1721f1f455f7..339cc02c06da6 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -30,11 +30,11 @@ use rustc_query_system::query::{ QueryCache, QueryContext, QueryDispatcher, QueryJobId, QueryMap, QuerySideEffect, QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query, }; -use rustc_query_system::{QueryOverflow, QueryOverflowNote}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::def_id::LOCAL_CRATE; use crate::QueryDispatcherUnerased; +use crate::error::{QueryOverflow, QueryOverflowNote}; /// Implements [`QueryContext`] for use by [`rustc_query_system`], since that /// crate does not have direct access to [`TyCtxt`]. diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 55f2feba0d861..adce85bf31be2 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -1,7 +1,6 @@ use rustc_errors::codes::*; -use rustc_hir::limit::Limit; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; #[derive(Subdiagnostic)] #[note("...which requires {$desc}...")] @@ -75,24 +74,3 @@ pub(crate) struct IncrementCompilation { pub run_cmd: String, pub dep_node: String, } - -#[derive(Diagnostic)] -#[help( - "consider increasing the recursion limit by adding a `#![recursion_limit = \"{$suggested_limit}\"]` attribute to your crate (`{$crate_name}`)" -)] -#[diag("queries overflow the depth limit!")] -pub struct QueryOverflow { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub note: QueryOverflowNote, - pub suggested_limit: Limit, - pub crate_name: Symbol, -} - -#[derive(Subdiagnostic)] -#[note("query depth increased by {$depth} when {$desc}")] -pub struct QueryOverflowNote { - pub desc: String, - pub depth: usize, -} diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 3175dbb54bea2..61edf397886b1 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -10,5 +10,3 @@ pub mod dep_graph; mod error; pub mod ich; pub mod query; - -pub use error::{QueryOverflow, QueryOverflowNote}; From 461e5ab448dea1c02591c38401e00f19c4e971d4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 3 Feb 2026 10:48:39 +1100 Subject: [PATCH 6/7] Remove `Cache::clear`. It's unused. And it's nice to remove this function that didn't behave like normal `clear` does, as the comment explained. --- compiler/rustc_query_system/src/cache.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs index 1b8332ad9e015..4217d0a49b91d 100644 --- a/compiler/rustc_query_system/src/cache.rs +++ b/compiler/rustc_query_system/src/cache.rs @@ -23,13 +23,6 @@ impl Default for Cache { } } -impl Cache { - /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` - pub fn clear(&self) { - *self.hashmap.borrow_mut() = Default::default(); - } -} - impl Cache { pub fn get(&self, key: &Key, tcx: Tcx) -> Option { Some(self.hashmap.borrow().get(key)?.get(tcx)) From 07e4a994d61dccda69135a7b50ce69f6d93deec8 Mon Sep 17 00:00:00 2001 From: Usman Akinyemi Date: Thu, 29 Jan 2026 14:07:41 +0530 Subject: [PATCH 7/7] citool: report debuginfo test statistics Extend CI postprocessing to aggregate pass/fail/ignored counts for debuginfo tests. Tests are identified via their reported suite names (e.g. debuginfo-gdb, debuginfo-lldb or debuginfo-cdb). Signed-off-by: Usman Akinyemi --- src/build_helper/src/metrics.rs | 23 +++++++++++++++++++++++ src/ci/citool/src/analysis.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index 07157e364158d..98dd952033e5c 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -111,6 +111,29 @@ pub struct JsonStepSystemStats { pub cpu_utilization_percent: f64, } +#[derive(Eq, Hash, PartialEq, Debug)] +pub enum DebuggerKind { + Gdb, + Lldb, + Cdb, +} + +impl DebuggerKind { + pub fn debuginfo_kind(name: &str) -> Option { + let name = name.to_ascii_lowercase(); + + if name.contains("debuginfo-gdb") { + Some(DebuggerKind::Gdb) + } else if name.contains("debuginfo-lldb") { + Some(DebuggerKind::Lldb) + } else if name.contains("debuginfo-cdb") { + Some(DebuggerKind::Cdb) + } else { + None + } + } +} + fn null_as_f64_nan<'de, D: serde::Deserializer<'de>>(d: D) -> Result { use serde::Deserialize as _; Option::::deserialize(d).map(|f| f.unwrap_or(f64::NAN)) diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 39b115154f9f4..ec65d9dcb5282 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use std::time::Duration; use build_helper::metrics::{ - BuildStep, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name, + BuildStep, DebuggerKind, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, escape_step_name, format_build_steps, }; @@ -139,11 +139,39 @@ fn record_test_suites(metrics: &JsonRoot) { let table = render_table(aggregated); println!("\n# Test results\n"); println!("{table}"); + report_debuginfo_statistics(&suites); } else { eprintln!("No test suites found in metrics"); } } +fn report_debuginfo_statistics(suites: &[&TestSuite]) { + let mut debugger_test_record: HashMap = HashMap::new(); + for suite in suites { + if let TestSuiteMetadata::Compiletest { .. } = suite.metadata { + for test in &suite.tests { + if let Some(kind) = DebuggerKind::debuginfo_kind(&test.name) { + let record = + debugger_test_record.entry(kind).or_insert(TestSuiteRecord::default()); + match test.outcome { + TestOutcome::Passed => record.passed += 1, + TestOutcome::Ignored { .. } => record.ignored += 1, + TestOutcome::Failed => record.failed += 1, + } + } + } + } + } + + println!("## DebugInfo Test Statistics"); + for (kind, record) in debugger_test_record { + println!( + "- {:?}: Passed ✅={}, Failed ❌={}, Ignored 🚫={}", + kind, record.passed, record.failed, record.ignored + ); + } +} + fn render_table(suites: BTreeMap) -> String { use std::fmt::Write;