From 0fc7d0485d465b5db3c69988da9bf751b80b3f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 11 Oct 2025 13:54:57 +0200 Subject: [PATCH 1/5] Move more early buffered lints to dyn lint diagnostics (5/N) --- compiler/rustc_lint/messages.ftl | 8 ---- compiler/rustc_lint/src/early/diagnostics.rs | 18 --------- compiler/rustc_lint/src/lints.rs | 38 ------------------ compiler/rustc_lint_defs/src/lib.rs | 10 +---- compiler/rustc_resolve/messages.ftl | 9 +++++ compiler/rustc_resolve/src/check_unused.rs | 6 ++- compiler/rustc_resolve/src/errors.rs | 41 +++++++++++++++++++- compiler/rustc_resolve/src/lib.rs | 3 +- compiler/rustc_resolve/src/macros.rs | 10 ++--- 9 files changed, 59 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bc0a98fc7aa8a..44c028ee50dc7 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -249,9 +249,6 @@ lint_expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message .rationale = {$rationale} -lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition - .suggestion = convert it to a `use` - lint_for_loops_over_fallibles = for loop over {$article} `{$ref_prefix}{$ty}`. This is more readably written as an `if let` statement .suggestion = consider using `if let` to clear intent @@ -453,9 +450,6 @@ lint_lintpass_by_hand = implementing `LintPass` by hand lint_macro_expr_fragment_specifier_2024_migration = the `expr` fragment specifier will accept more expressions in the 2024 edition .suggestion = to keep the existing behavior, use the `expr_2021` fragment specifier -lint_macro_is_private = macro `{$ident}` is private - -lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used lint_malformed_attribute = malformed lint attribute input @@ -948,8 +942,6 @@ lint_unused_imports = {$num_snippets -> lint_unused_lifetime = lifetime parameter `{$ident}` never used .suggestion = elide the unused lifetime -lint_unused_macro_definition = unused macro definition: `{$name}` - lint_unused_op = unused {$op} that must be used .label = the {$op} produces a value .suggestion = use `let _ = ...` to ignore the resulting value diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 9029ee0447110..16f50933eb0de 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -251,12 +251,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => { - let suggestion_span = vis_span.between(ident_span); - let code = if vis_span.is_empty() { "use " } else { " use " }; - - lints::ExternCrateNotIdiomatic { span: suggestion_span, code }.decorate_lint(diag); - } BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => { lints::AmbiguousGlobImports { ambiguity }.decorate_lint(diag); } @@ -332,18 +326,6 @@ pub fn decorate_builtin_lint( lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() } .decorate_lint(diag); } - BuiltinLintDiag::MacroIsPrivate(ident) => { - lints::MacroIsPrivate { ident }.decorate_lint(diag); - } - BuiltinLintDiag::UnusedMacroDefinition(name) => { - lints::UnusedMacroDefinition { name }.decorate_lint(diag); - } - BuiltinLintDiag::MacroRuleNeverUsed(n, name) => { - lints::MacroRuleNeverUsed { n: n + 1, name }.decorate_lint(diag); - } - BuiltinLintDiag::UnstableFeature(msg) => { - lints::UnstableFeature { msg }.decorate_lint(diag); - } BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index b7312484de5cd..da22c387af708 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2543,35 +2543,6 @@ pub(crate) struct PrivateExternCrateReexport { pub sugg: Span, } -#[derive(LintDiagnostic)] -#[diag(lint_macro_is_private)] -pub(crate) struct MacroIsPrivate { - pub ident: Ident, -} - -#[derive(LintDiagnostic)] -#[diag(lint_unused_macro_definition)] -pub(crate) struct UnusedMacroDefinition { - pub name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(lint_macro_rule_never_used)] -pub(crate) struct MacroRuleNeverUsed { - pub n: usize, - pub name: Symbol, -} - -pub(crate) struct UnstableFeature { - pub msg: DiagMessage, -} - -impl<'a> LintDiagnostic<'a, ()> for UnstableFeature { - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { - diag.primary_message(self.msg); - } -} - #[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] #[help] @@ -2853,15 +2824,6 @@ pub(crate) struct NamedArgumentUsedPositionally { pub named_arg_name: String, } -#[derive(LintDiagnostic)] -#[diag(lint_extern_crate_not_idiomatic)] -pub(crate) struct ExternCrateNotIdiomatic { - #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")] - pub span: Span, - - pub code: &'static str, -} - // FIXME: make this translatable pub(crate) struct AmbiguousGlobImports { pub ambiguity: AmbiguityErrorDiag, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 40a818a3c9dc7..d0eeae0c9e7d8 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; -use rustc_error_messages::{DiagArgValue, DiagMessage, IntoDiagArg, MultiSpan}; +use rustc_error_messages::{DiagArgValue, IntoDiagArg, MultiSpan}; use rustc_hir_id::{HashStableContext, HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::DefPathHash; @@ -678,10 +678,6 @@ pub enum BuiltinLintDiag { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, - ExternCrateNotIdiomatic { - vis_span: Span, - ident_span: Span, - }, AmbiguousGlobImports { diag: AmbiguityErrorDiag, }, @@ -731,10 +727,6 @@ pub enum BuiltinLintDiag { source: Ident, extern_crate_span: Span, }, - MacroIsPrivate(Ident), - UnusedMacroDefinition(Symbol), - MacroRuleNeverUsed(usize, Symbol), - UnstableFeature(DiagMessage), UnusedCrateDependency { extern_crate: Symbol, local_crate: Symbol, diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 5bf90d2637df5..6a16f49ce8cf7 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -146,6 +146,9 @@ resolve_explicit_unsafe_traits = resolve_extern_crate_loading_macro_not_at_crate_root = an `extern crate` loading macros must be at the crate root +resolve_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition + .suggestion = convert it to a `use` + resolve_extern_crate_self_requires_renaming = `extern crate self;` requires renaming .suggestion = rename the `self` crate to be able to import it @@ -274,6 +277,10 @@ resolve_macro_extern_deprecated = `#[macro_escape]` is a deprecated synonym for `#[macro_use]` .help = try an outer attribute: `#[macro_use]` +resolve_macro_is_private = macro `{$ident}` is private + +resolve_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used + resolve_macro_use_deprecated = applying the `#[macro_use]` attribute to an `extern crate` item is deprecated .help = remove it and import macros at use sites with a `use` item instead @@ -487,6 +494,8 @@ resolve_unused_extern_crate = unused extern crate resolve_unused_label = unused label +resolve_unused_macro_definition = unused macro definition: `{$name}` + resolve_unused_macro_use = unused `#[macro_use]` import resolve_variable_bound_with_different_mode = diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 95f979a3fed33..52c2ac2d8e64a 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -228,11 +228,15 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { .span .find_ancestor_inside(extern_crate.span) .unwrap_or(extern_crate.ident.span); + self.r.lint_buffer.buffer_lint( UNUSED_EXTERN_CRATES, extern_crate.id, extern_crate.span, - BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span }, + crate::errors::ExternCrateNotIdiomatic { + span: vis_span.between(ident_span), + code: if vis_span.is_empty() { "use " } else { " use " }, + }, ); } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index f0ea97ba8a0c0..c1ef2860d2473 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, MultiSpan, - Subdiagnostic, + Applicability, Diag, DiagMessage, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, + LintDiagnostic, MultiSpan, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -1329,3 +1329,40 @@ pub(crate) struct UnusedMacroUse; #[diag(resolve_macro_use_deprecated)] #[help] pub(crate) struct MacroUseDeprecated; + +#[derive(LintDiagnostic)] +#[diag(resolve_macro_is_private)] +pub(crate) struct MacroIsPrivate { + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_unused_macro_definition)] +pub(crate) struct UnusedMacroDefinition { + pub name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_macro_rule_never_used)] +pub(crate) struct MacroRuleNeverUsed { + pub n: usize, + pub name: Symbol, +} + +pub(crate) struct UnstableFeature { + pub msg: DiagMessage, +} + +impl<'a> LintDiagnostic<'a, ()> for UnstableFeature { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + diag.primary_message(self.msg); + } +} + +#[derive(LintDiagnostic)] +#[diag(resolve_extern_crate_not_idiomatic)] +pub(crate) struct ExternCrateNotIdiomatic { + #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")] + pub span: Span, + pub code: &'static str, +} diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d9c3f4089a0fb..e0ae11595a02e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -73,7 +73,6 @@ use rustc_middle::ty::{ ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; @@ -2075,7 +2074,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PRIVATE_MACRO_USE, import.root_id, ident.span, - BuiltinLintDiag::MacroIsPrivate(ident), + errors::MacroIsPrivate { ident }, ); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c50dfd41b51c8..d4dd2fdd6bef5 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -341,7 +341,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { UNUSED_MACROS, node_id, ident.span, - BuiltinLintDiag::UnusedMacroDefinition(ident.name), + errors::UnusedMacroDefinition { name: ident.name }, ); // Do not report unused individual rules if the entire macro is unused self.unused_macro_rules.swap_remove(&node_id); @@ -362,7 +362,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { UNUSED_MACRO_RULES, node_id, rule_span, - BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name), + errors::MacroRuleNeverUsed { n: arm_i + 1, name: ident.name }, ); } } @@ -1041,10 +1041,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lint, node_id, span, - BuiltinLintDiag::UnstableFeature( - // FIXME make this translatable - msg.into(), - ), + // FIXME make this translatable + errors::UnstableFeature { msg: msg.into() }, ) }; stability::report_unstable( From 7ec1804f3273e3dd028ed2406b69591949393034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 11 Oct 2025 15:52:36 +0200 Subject: [PATCH 2/5] Move more early buffered lints to dyn lint diagnostics (6/N) --- compiler/rustc_lint/messages.ftl | 14 ------ compiler/rustc_lint/src/early/diagnostics.rs | 18 ------- compiler/rustc_lint/src/lints.rs | 50 -------------------- compiler/rustc_lint_defs/src/lib.rs | 18 ------- compiler/rustc_resolve/messages.ftl | 14 ++++++ compiler/rustc_resolve/src/errors.rs | 49 +++++++++++++++++++ compiler/rustc_resolve/src/imports.rs | 12 +++-- compiler/rustc_resolve/src/macros.rs | 21 ++++---- 8 files changed, 81 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 44c028ee50dc7..2b3f16d65c381 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -628,10 +628,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass lint_opaque_hidden_inferred_bound_sugg = add this bound -lint_out_of_scope_macro_calls = cannot find macro `{$path}` in the current scope when looking from {$location} - .label = not found from {$location} - .help = import `macro_rules` with `use` to make it callable above its definition - lint_overflowing_bin_hex = literal out of range for `{$ty}` .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` @@ -667,9 +663,6 @@ lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations .label = pattern not allowed in foreign function -lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported - .suggestion = consider making the `extern crate` item publicly accessible - lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale @@ -695,10 +688,6 @@ lint_redundant_import = the item `{$ident}` is imported redundantly .label_imported_prelude = the item `{$ident}` is already imported by the extern prelude .label_defined_prelude = the item `{$ident}` is already defined by the extern prelude -lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough - .note = the most public imported item is `{$max_vis}` - .help = reduce the glob import's visibility or increase visibility of imported items - lint_redundant_semicolons = unnecessary trailing {$multiple -> [true] semicolons @@ -858,9 +847,6 @@ lint_unicode_text_flow = unicode codepoint changing visible direction of text pr lint_unit_bindings = binding has unit type `()` .label = this pattern is inferred to be the unit type `()` -lint_unknown_diagnostic_attribute = unknown diagnostic attribute -lint_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists - lint_unknown_gated_lint = unknown lint: `{$name}` .note = the `{$name}` lint is unstable diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 16f50933eb0de..34bb3989008ea 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -311,21 +311,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => { - lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis } - .decorate_lint(diag); - } - BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => { - let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg { - span: typo_span, - typo_name, - }); - lints::UnknownDiagnosticAttribute { typo }.decorate_lint(diag); - } - BuiltinLintDiag::PrivateExternCrateReexport { source: ident, extern_crate_span } => { - lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() } - .decorate_lint(diag); - } BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } @@ -340,8 +325,5 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag) } - BuiltinLintDiag::OutOfScopeMacroCalls { span, path, location } => { - lints::OutOfScopeMacroCalls { span, path, location }.decorate_lint(diag) - } } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index da22c387af708..87414ce9b9788 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2535,14 +2535,6 @@ pub(crate) mod unexpected_cfg_value { } } -#[derive(LintDiagnostic)] -#[diag(lint_private_extern_crate_reexport, code = E0365)] -pub(crate) struct PrivateExternCrateReexport { - pub ident: Ident, - #[suggestion(code = "pub ", style = "verbose", applicability = "maybe-incorrect")] - pub sugg: Span, -} - #[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] #[help] @@ -2562,26 +2554,6 @@ pub(crate) struct IllFormedAttributeInput { pub docs: &'static str, } -#[derive(LintDiagnostic)] -#[diag(lint_unknown_diagnostic_attribute)] -pub(crate) struct UnknownDiagnosticAttribute { - #[subdiagnostic] - pub typo: Option, -} - -#[derive(Subdiagnostic)] -#[suggestion( - lint_unknown_diagnostic_attribute_typo_sugg, - style = "verbose", - code = "{typo_name}", - applicability = "machine-applicable" -)] -pub(crate) struct UnknownDiagnosticAttributeTypoSugg { - #[primary_span] - pub span: Span, - pub typo_name: Symbol, -} - #[derive(LintDiagnostic)] #[diag(lint_unicode_text_flow)] #[note] @@ -2881,18 +2853,6 @@ pub(crate) struct AssociatedConstElidedLifetime { pub lifetimes_in_scope: MultiSpan, } -#[derive(LintDiagnostic)] -#[diag(lint_redundant_import_visibility)] -pub(crate) struct RedundantImportVisibility { - #[note] - pub span: Span, - #[help] - pub help: (), - - pub import_vis: String, - pub max_vis: String, -} - #[derive(LintDiagnostic)] #[diag(lint_unsafe_attr_outside_unsafe)] pub(crate) struct UnsafeAttrOutsideUnsafe { @@ -2914,16 +2874,6 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { pub right: Span, } -#[derive(LintDiagnostic)] -#[diag(lint_out_of_scope_macro_calls)] -#[help] -pub(crate) struct OutOfScopeMacroCalls { - #[label] - pub span: Span, - pub path: String, - pub location: String, -} - #[derive(LintDiagnostic)] #[diag(lint_static_mut_refs_lint)] pub(crate) struct RefOfMutStatic<'a> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index d0eeae0c9e7d8..b4ddf00c0234d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -714,19 +714,6 @@ pub enum BuiltinLintDiag { span: Span, lifetimes_in_scope: MultiSpan, }, - RedundantImportVisibility { - span: Span, - max_vis: String, - import_vis: String, - }, - UnknownDiagnosticAttribute { - span: Span, - typo_name: Option, - }, - PrivateExternCrateReexport { - source: Ident, - extern_crate_span: Span, - }, UnusedCrateDependency { extern_crate: Symbol, local_crate: Symbol, @@ -735,11 +722,6 @@ pub enum BuiltinLintDiag { suggestions: Vec, docs: Option<&'static str>, }, - OutOfScopeMacroCalls { - span: Span, - path: String, - location: String, - }, } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 6a16f49ce8cf7..5ca93dbb6806a 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -336,6 +336,10 @@ resolve_note_and_refers_to_the_item_defined_here = } } +resolve_out_of_scope_macro_calls = cannot find macro `{$path}` in the current scope when looking from {$location} + .label = not found from {$location} + .help = import `macro_rules` with `use` to make it callable above its definition + resolve_outer_ident_is_not_publicly_reexported = {$outer_ident_descr} `{$outer_ident}` is not publicly re-exported @@ -356,12 +360,19 @@ resolve_param_in_ty_of_const_param = resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}` +resolve_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported + .suggestion = consider making the `extern crate` item publicly accessible + resolve_proc_macro_derive_resolution_fallback = cannot find {$ns_descr} `{$ident}` in this scope .label = names from parent modules are not accessible without an explicit import resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it .help = you can define integration tests in a directory named `tests` +resolve_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough + .note = the most public imported item is `{$max_vis}` + .help = reduce the glob import's visibility or increase visibility of imported items + resolve_reexport_of_crate_public = re-export of crate public `{$ident}` @@ -467,6 +478,9 @@ resolve_unexpected_res_change_ty_to_const_param_sugg = resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg = if you meant to collect the rest of the slice in `{$ident}`, use the at operator +resolve_unknown_diagnostic_attribute = unknown diagnostic attribute +resolve_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists + resolve_unnamed_crate_root_import = crate root imports need to be explicitly named: `use crate as name;` diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index c1ef2860d2473..e5a879b919cec 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -784,6 +784,14 @@ pub(crate) struct CannotBeReexportedCratePublicNS { pub(crate) ident: Ident, } +#[derive(LintDiagnostic)] +#[diag(resolve_private_extern_crate_reexport, code = E0365)] +pub(crate) struct PrivateExternCrateReexport { + pub ident: Ident, + #[suggestion(code = "pub ", style = "verbose", applicability = "maybe-incorrect")] + pub sugg: Span, +} + #[derive(Subdiagnostic)] #[help(resolve_consider_adding_macro_export)] pub(crate) struct ConsiderAddingMacroExport { @@ -1366,3 +1374,44 @@ pub(crate) struct ExternCrateNotIdiomatic { pub span: Span, pub code: &'static str, } + +#[derive(LintDiagnostic)] +#[diag(resolve_out_of_scope_macro_calls)] +#[help] +pub(crate) struct OutOfScopeMacroCalls { + #[label] + pub span: Span, + pub path: String, + pub location: String, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_redundant_import_visibility)] +pub(crate) struct RedundantImportVisibility { + #[note] + pub span: Span, + #[help] + pub help: (), + pub import_vis: String, + pub max_vis: String, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_unknown_diagnostic_attribute)] +pub(crate) struct UnknownDiagnosticAttribute { + #[subdiagnostic] + pub typo: Option, +} + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_unknown_diagnostic_attribute_typo_sugg, + style = "verbose", + code = "{typo_name}", + applicability = "machine-applicable" +)] +pub(crate) struct UnknownDiagnosticAttributeTypoSugg { + #[primary_span] + pub span: Span, + pub typo_name: Symbol, +} diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 04eb312a0f8ba..2023976770a3a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1103,10 +1103,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { UNUSED_IMPORTS, id, import.span, - BuiltinLintDiag::RedundantImportVisibility { + crate::errors::RedundantImportVisibility { + span: import.span, + help: (), max_vis: max_vis.to_string(def_id, self.tcx), import_vis: import.vis.to_string(def_id, self.tcx), - span: import.span, }, ); } @@ -1338,13 +1339,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !any_successful_reexport { let (ns, binding) = reexport_error.unwrap(); if let Some(extern_crate_id) = pub_use_of_private_extern_crate_hack(import, binding) { + let extern_crate_sp = self.tcx.source_span(self.local_def_id(extern_crate_id)); self.lint_buffer.buffer_lint( PUB_USE_OF_PRIVATE_EXTERN_CRATE, import_id, import.span, - BuiltinLintDiag::PrivateExternCrateReexport { - source: ident, - extern_crate_span: self.tcx.source_span(self.local_def_id(extern_crate_id)), + crate::errors::PrivateExternCrateReexport { + ident, + sugg: extern_crate_sp.shrink_to_lo(), }, ); } else if ns == TypeNS { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d4dd2fdd6bef5..db112a221325a 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -22,7 +22,6 @@ use rustc_hir::def::{self, DefKind, MacroKinds, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; use rustc_middle::ty::{RegisteredTools, TyCtxt}; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACRO_RULES, UNUSED_MACROS, @@ -685,22 +684,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit(); } + const DIAG_ATTRS: &[Symbol] = &[sym::on_unimplemented, sym::do_not_recommend]; + if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) && let [namespace, attribute, ..] = &*path.segments && namespace.ident.name == sym::diagnostic - && ![sym::on_unimplemented, sym::do_not_recommend].contains(&attribute.ident.name) + && !DIAG_ATTRS.contains(&attribute.ident.name) { - let typo_name = find_best_match_for_name( - &[sym::on_unimplemented, sym::do_not_recommend], - attribute.ident.name, - Some(5), - ); + let span = attribute.span(); + + let typo = find_best_match_for_name(DIAG_ATTRS, attribute.ident.name, Some(5)) + .map(|typo_name| errors::UnknownDiagnosticAttributeTypoSugg { span, typo_name }); self.tcx.sess.psess.buffer_lint( UNKNOWN_DIAGNOSTIC_ATTRIBUTES, - attribute.span(), + span, node_id, - BuiltinLintDiag::UnknownDiagnosticAttribute { span: attribute.span(), typo_name }, + errors::UnknownDiagnosticAttribute { typo }, ); } @@ -1134,9 +1134,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { OUT_OF_SCOPE_MACRO_CALLS, path.span, node_id, - BuiltinLintDiag::OutOfScopeMacroCalls { + errors::OutOfScopeMacroCalls { span: path.span, path: pprust::path_to_string(path), + // FIXME: Make this translatable. location, }, ); From 1a4e8e8fb915fd7f7a0d00aabf2197af88b6903c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 11 Oct 2025 18:25:10 +0200 Subject: [PATCH 3/5] Move early buffered lint ambigous-glob-imports to a dyn lint diagnostic --- compiler/rustc_errors/src/lib.rs | 16 ------- compiler/rustc_lint/src/early/diagnostics.rs | 3 -- compiler/rustc_lint/src/lints.rs | 13 ------ compiler/rustc_lint_defs/src/lib.rs | 18 -------- compiler/rustc_resolve/src/diagnostics.rs | 43 ++++++++--------- compiler/rustc_resolve/src/errors.rs | 46 ++++++++++++++++++- tests/ui/imports/ambiguous-1.stderr | 5 +- tests/ui/imports/ambiguous-10.stderr | 5 +- tests/ui/imports/ambiguous-12.stderr | 5 +- tests/ui/imports/ambiguous-13.stderr | 5 +- tests/ui/imports/ambiguous-14.stderr | 5 +- tests/ui/imports/ambiguous-15.stderr | 5 +- tests/ui/imports/ambiguous-16.stderr | 5 +- tests/ui/imports/ambiguous-17.stderr | 5 +- tests/ui/imports/ambiguous-3.stderr | 5 +- tests/ui/imports/ambiguous-4-extern.stderr | 5 +- tests/ui/imports/ambiguous-5.stderr | 5 +- tests/ui/imports/ambiguous-6.stderr | 5 +- tests/ui/imports/ambiguous-9.stderr | 9 ++-- tests/ui/imports/duplicate.stderr | 12 ++--- .../unresolved-seg-after-ambiguous.stderr | 7 +-- 21 files changed, 113 insertions(+), 114 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 8869799ce90d9..9dd3c5902d44a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2035,22 +2035,6 @@ pub fn elided_lifetime_in_path_suggestion( ElidedLifetimeInPathSubdiag { expected, indicate } } -pub fn report_ambiguity_error<'a, G: EmissionGuarantee>( - diag: &mut Diag<'a, G>, - ambiguity: rustc_lint_defs::AmbiguityErrorDiag, -) { - diag.span_label(ambiguity.label_span, ambiguity.label_msg); - diag.note(ambiguity.note_msg); - diag.span_note(ambiguity.b1_span, ambiguity.b1_note_msg); - for help_msg in ambiguity.b1_help_msgs { - diag.help(help_msg); - } - diag.span_note(ambiguity.b2_span, ambiguity.b2_note_msg); - for help_msg in ambiguity.b2_help_msgs { - diag.help(help_msg); - } -} - /// Grammatical tool for displaying messages to end users in a nice form. /// /// Returns "an" if the given string starts with a vowel, and "a" otherwise. diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 34bb3989008ea..e376d7d2ab883 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -251,9 +251,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => { - lints::AmbiguousGlobImports { ambiguity }.decorate_lint(diag); - } BuiltinLintDiag::AmbiguousGlobReexports { name, namespace, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 87414ce9b9788..f99d3fc5e98e3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -15,7 +15,6 @@ use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; -use rustc_session::lint::AmbiguityErrorDiag; use rustc_span::edition::Edition; use rustc_span::{Ident, Span, Symbol, sym}; @@ -2796,18 +2795,6 @@ pub(crate) struct NamedArgumentUsedPositionally { pub named_arg_name: String, } -// FIXME: make this translatable -pub(crate) struct AmbiguousGlobImports { - pub ambiguity: AmbiguityErrorDiag, -} - -impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports { - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { - diag.primary_message(self.ambiguity.msg.clone()); - rustc_errors::report_ambiguity_error(diag, self.ambiguity); - } -} - #[derive(LintDiagnostic)] #[diag(lint_ambiguous_glob_reexport)] pub(crate) struct AmbiguousGlobReexports { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index b4ddf00c0234d..0ddc2e3076e92 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -593,21 +593,6 @@ impl StableCompare for LintId { } } -#[derive(Debug)] -pub struct AmbiguityErrorDiag { - pub msg: String, - pub span: Span, - pub label_span: Span, - pub label_msg: String, - pub note_msg: String, - pub b1_span: Span, - pub b1_note_msg: String, - pub b1_help_msgs: Vec, - pub b2_span: Span, - pub b2_note_msg: String, - pub b2_help_msgs: Vec, -} - #[derive(Debug, Clone)] pub enum DeprecatedSinceKind { InEffect, @@ -678,9 +663,6 @@ pub enum BuiltinLintDiag { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, - AmbiguousGlobImports { - diag: AmbiguityErrorDiag, - }, AmbiguousGlobReexports { /// The name for which collision(s) have occurred. name: String, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 236ab1f09d35f..ad62b6a1827c5 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -9,7 +9,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, - report_ambiguity_error, struct_span_code_err, + struct_span_code_err, }; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; @@ -20,16 +20,16 @@ use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr}; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, }; -use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag}; use rustc_session::utils::was_invoked_from_cargo; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::SourceMap; +use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::{BytePos, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, instrument}; @@ -143,7 +143,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } for ambiguity_error in &self.ambiguity_errors { - let diag = self.ambiguity_diagnostics(ambiguity_error); + let diag = self.ambiguity_diagnostic(ambiguity_error); + if ambiguity_error.warning { let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else { unreachable!() @@ -151,13 +152,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.lint_buffer.buffer_lint( AMBIGUOUS_GLOB_IMPORTS, import.root_id, - ambiguity_error.ident.span, - BuiltinLintDiag::AmbiguousGlobImports { diag }, + diag.ident.span, + diag, ); } else { - let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", diag.msg); - report_ambiguity_error(&mut err, diag); - err.emit(); + self.dcx().emit_err(diag); } } @@ -1982,7 +1981,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'ra>) -> AmbiguityErrorDiag { + fn ambiguity_diagnostic(&self, ambiguity_error: &AmbiguityError<'ra>) -> errors::Ambiguity { let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; let extern_prelude_ambiguity = || { self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { @@ -2025,8 +2024,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } ( - b.span, - note_msg, + Spanned { node: note_msg, span: b.span }, help_msgs .iter() .enumerate() @@ -2037,20 +2035,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect::>(), ) }; - let (b1_span, b1_note_msg, b1_help_msgs) = could_refer_to(b1, misc1, ""); - let (b2_span, b2_note_msg, b2_help_msgs) = could_refer_to(b2, misc2, " also"); - - AmbiguityErrorDiag { - msg: format!("`{ident}` is ambiguous"), - span: ident.span, - label_span: ident.span, - label_msg: "ambiguous name".to_string(), - note_msg: format!("ambiguous because of {}", kind.descr()), - b1_span, - b1_note_msg, + let (b1_note, b1_help_msgs) = could_refer_to(b1, misc1, ""); + let (b2_note, b2_help_msgs) = could_refer_to(b2, misc2, " also"); + + errors::Ambiguity { + ident, + kind: kind.descr(), + b1_note, b1_help_msgs, - b2_span, - b2_note_msg, + b2_note, b2_help_msgs, } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e5a879b919cec..719398321335d 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,9 +1,10 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagMessage, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, - LintDiagnostic, MultiSpan, Subdiagnostic, + Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, ElidedLifetimeInPathSubdiag, + EmissionGuarantee, IntoDiagArg, Level, LintDiagnostic, MultiSpan, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span, Symbol}; use crate::late::PatternSource; @@ -1415,3 +1416,44 @@ pub(crate) struct UnknownDiagnosticAttributeTypoSugg { pub span: Span, pub typo_name: Symbol, } + +// FIXME: Make this properly translatable. +pub(crate) struct Ambiguity { + pub ident: Ident, + pub kind: &'static str, + pub b1_note: Spanned, + pub b1_help_msgs: Vec, + pub b2_note: Spanned, + pub b2_help_msgs: Vec, +} + +impl Ambiguity { + fn decorate<'a>(self, diag: &mut Diag<'a, impl EmissionGuarantee>) { + diag.primary_message(format!("`{}` is ambiguous", self.ident)); + diag.code(E0759); + diag.span_label(self.ident.span, "ambiguous name"); + diag.note(format!("ambiguous because of {}", self.kind)); + diag.span_note(self.b1_note.span, self.b1_note.node); + for help_msg in self.b1_help_msgs { + diag.help(help_msg); + } + diag.span_note(self.b2_note.span, self.b2_note.node); + for help_msg in self.b2_help_msgs { + diag.help(help_msg); + } + } +} + +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Ambiguity { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { + let mut diag = Diag::new(dcx, level, "").with_span(self.ident.span); + self.decorate(&mut diag); + diag + } +} + +impl<'a> LintDiagnostic<'a, ()> for Ambiguity { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + self.decorate(diag); + } +} diff --git a/tests/ui/imports/ambiguous-1.stderr b/tests/ui/imports/ambiguous-1.stderr index 04ff3a36c7467..9091eb0aeb58e 100644 --- a/tests/ui/imports/ambiguous-1.stderr +++ b/tests/ui/imports/ambiguous-1.stderr @@ -9,7 +9,7 @@ LL | pub use self::handwritten::*; | = note: `#[warn(ambiguous_glob_reexports)]` on by default -warning: `id` is ambiguous +warning[E0759]: `id` is ambiguous --> $DIR/ambiguous-1.rs:29:5 | LL | id(); @@ -38,8 +38,9 @@ LL | #![warn(ambiguous_glob_imports)] warning: 2 warnings emitted +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -warning: `id` is ambiguous +warning[E0759]: `id` is ambiguous --> $DIR/ambiguous-1.rs:29:5 | LL | id(); diff --git a/tests/ui/imports/ambiguous-10.stderr b/tests/ui/imports/ambiguous-10.stderr index f175d27c99e98..729fe2054a749 100644 --- a/tests/ui/imports/ambiguous-10.stderr +++ b/tests/ui/imports/ambiguous-10.stderr @@ -1,4 +1,4 @@ -error: `Token` is ambiguous +error[E0759]: `Token` is ambiguous --> $DIR/ambiguous-10.rs:15:9 | LL | fn c(_: Token) {} @@ -23,8 +23,9 @@ LL | use crate::b::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `Token` is ambiguous +error[E0759]: `Token` is ambiguous --> $DIR/ambiguous-10.rs:15:9 | LL | fn c(_: Token) {} diff --git a/tests/ui/imports/ambiguous-12.stderr b/tests/ui/imports/ambiguous-12.stderr index 5f92eae0dbcb1..f265d1aca9379 100644 --- a/tests/ui/imports/ambiguous-12.stderr +++ b/tests/ui/imports/ambiguous-12.stderr @@ -1,4 +1,4 @@ -error: `b` is ambiguous +error[E0759]: `b` is ambiguous --> $DIR/ambiguous-12.rs:21:5 | LL | b(); @@ -23,8 +23,9 @@ LL | use crate::public::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `b` is ambiguous +error[E0759]: `b` is ambiguous --> $DIR/ambiguous-12.rs:21:5 | LL | b(); diff --git a/tests/ui/imports/ambiguous-13.stderr b/tests/ui/imports/ambiguous-13.stderr index 279b4e8f1420a..afc0bbe97f484 100644 --- a/tests/ui/imports/ambiguous-13.stderr +++ b/tests/ui/imports/ambiguous-13.stderr @@ -1,4 +1,4 @@ -error: `Rect` is ambiguous +error[E0759]: `Rect` is ambiguous --> $DIR/ambiguous-13.rs:18:9 | LL | fn a(_: Rect) {} @@ -23,8 +23,9 @@ LL | use crate::content::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `Rect` is ambiguous +error[E0759]: `Rect` is ambiguous --> $DIR/ambiguous-13.rs:18:9 | LL | fn a(_: Rect) {} diff --git a/tests/ui/imports/ambiguous-14.stderr b/tests/ui/imports/ambiguous-14.stderr index ef7e2669bae4c..41e57067da882 100644 --- a/tests/ui/imports/ambiguous-14.stderr +++ b/tests/ui/imports/ambiguous-14.stderr @@ -1,4 +1,4 @@ -error: `foo` is ambiguous +error[E0759]: `foo` is ambiguous --> $DIR/ambiguous-14.rs:22:8 | LL | g::foo(); @@ -23,8 +23,9 @@ LL | pub use b::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `foo` is ambiguous +error[E0759]: `foo` is ambiguous --> $DIR/ambiguous-14.rs:22:8 | LL | g::foo(); diff --git a/tests/ui/imports/ambiguous-15.stderr b/tests/ui/imports/ambiguous-15.stderr index 15f83546532ec..88ef7bdffdc07 100644 --- a/tests/ui/imports/ambiguous-15.stderr +++ b/tests/ui/imports/ambiguous-15.stderr @@ -1,4 +1,4 @@ -error: `Error` is ambiguous +error[E0759]: `Error` is ambiguous --> $DIR/ambiguous-15.rs:22:9 | LL | fn a(_: E) {} @@ -23,8 +23,9 @@ LL | pub use t2::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `Error` is ambiguous +error[E0759]: `Error` is ambiguous --> $DIR/ambiguous-15.rs:22:9 | LL | fn a(_: E) {} diff --git a/tests/ui/imports/ambiguous-16.stderr b/tests/ui/imports/ambiguous-16.stderr index 7c80dee17f040..f2c474d0312df 100644 --- a/tests/ui/imports/ambiguous-16.stderr +++ b/tests/ui/imports/ambiguous-16.stderr @@ -1,4 +1,4 @@ -error: `ConfirmedTranscriptHashInput` is ambiguous +error[E0759]: `ConfirmedTranscriptHashInput` is ambiguous --> $DIR/ambiguous-16.rs:22:21 | LL | use crate::framing::ConfirmedTranscriptHashInput; @@ -23,8 +23,9 @@ LL | pub use self::public_message_in::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `ConfirmedTranscriptHashInput` is ambiguous +error[E0759]: `ConfirmedTranscriptHashInput` is ambiguous --> $DIR/ambiguous-16.rs:22:21 | LL | use crate::framing::ConfirmedTranscriptHashInput; diff --git a/tests/ui/imports/ambiguous-17.stderr b/tests/ui/imports/ambiguous-17.stderr index 38491ce10628d..a5cf72402240a 100644 --- a/tests/ui/imports/ambiguous-17.stderr +++ b/tests/ui/imports/ambiguous-17.stderr @@ -8,7 +8,7 @@ LL | pub use handwritten::*; | = note: `#[warn(ambiguous_glob_reexports)]` on by default -error: `id` is ambiguous +error[E0759]: `id` is ambiguous --> $DIR/ambiguous-17.rs:25:5 | LL | id(); @@ -33,8 +33,9 @@ LL | pub use handwritten::*; error: aborting due to 1 previous error; 1 warning emitted +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `id` is ambiguous +error[E0759]: `id` is ambiguous --> $DIR/ambiguous-17.rs:25:5 | LL | id(); diff --git a/tests/ui/imports/ambiguous-3.stderr b/tests/ui/imports/ambiguous-3.stderr index 27fa05a195b94..2451699aeebf1 100644 --- a/tests/ui/imports/ambiguous-3.stderr +++ b/tests/ui/imports/ambiguous-3.stderr @@ -1,4 +1,4 @@ -error: `x` is ambiguous +error[E0759]: `x` is ambiguous --> $DIR/ambiguous-3.rs:5:5 | LL | x(); @@ -23,8 +23,9 @@ LL | pub use self::c::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `x` is ambiguous +error[E0759]: `x` is ambiguous --> $DIR/ambiguous-3.rs:5:5 | LL | x(); diff --git a/tests/ui/imports/ambiguous-4-extern.stderr b/tests/ui/imports/ambiguous-4-extern.stderr index a9427ac03504b..35220b7758003 100644 --- a/tests/ui/imports/ambiguous-4-extern.stderr +++ b/tests/ui/imports/ambiguous-4-extern.stderr @@ -8,7 +8,7 @@ LL | pub use handwritten::*; | = note: `#[warn(ambiguous_glob_reexports)]` on by default -warning: `id` is ambiguous +warning[E0759]: `id` is ambiguous --> $DIR/ambiguous-4-extern.rs:25:5 | LL | id(); @@ -37,8 +37,9 @@ LL | #![warn(ambiguous_glob_imports)] warning: 2 warnings emitted +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -warning: `id` is ambiguous +warning[E0759]: `id` is ambiguous --> $DIR/ambiguous-4-extern.rs:25:5 | LL | id(); diff --git a/tests/ui/imports/ambiguous-5.stderr b/tests/ui/imports/ambiguous-5.stderr index 1fc5f4543f358..b9ec4b424a269 100644 --- a/tests/ui/imports/ambiguous-5.stderr +++ b/tests/ui/imports/ambiguous-5.stderr @@ -1,4 +1,4 @@ -error: `Class` is ambiguous +error[E0759]: `Class` is ambiguous --> $DIR/ambiguous-5.rs:12:23 | LL | struct MarkRecord(Class); @@ -23,8 +23,9 @@ LL | use super::gsubgpos::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `Class` is ambiguous +error[E0759]: `Class` is ambiguous --> $DIR/ambiguous-5.rs:12:23 | LL | struct MarkRecord(Class); diff --git a/tests/ui/imports/ambiguous-6.stderr b/tests/ui/imports/ambiguous-6.stderr index 681bc40931f52..59cf3b924410e 100644 --- a/tests/ui/imports/ambiguous-6.stderr +++ b/tests/ui/imports/ambiguous-6.stderr @@ -1,4 +1,4 @@ -error: `C` is ambiguous +error[E0759]: `C` is ambiguous --> $DIR/ambiguous-6.rs:6:5 | LL | C @@ -23,8 +23,9 @@ LL | pub use mod2::*; error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `C` is ambiguous +error[E0759]: `C` is ambiguous --> $DIR/ambiguous-6.rs:6:5 | LL | C diff --git a/tests/ui/imports/ambiguous-9.stderr b/tests/ui/imports/ambiguous-9.stderr index 800a2e10c9d78..76e316d519ef4 100644 --- a/tests/ui/imports/ambiguous-9.stderr +++ b/tests/ui/imports/ambiguous-9.stderr @@ -8,7 +8,7 @@ LL | use super::prelude::*; | = note: `#[warn(ambiguous_glob_reexports)]` on by default -error: `date_range` is ambiguous +error[E0759]: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); @@ -39,7 +39,7 @@ LL | pub use self::t::*; LL | pub use super::dsl::*; | ------------- but the name `date_range` in the value namespace is also re-exported here -error: `date_range` is ambiguous +error[E0759]: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); @@ -63,8 +63,9 @@ LL | use prelude::*; error: aborting due to 2 previous errors; 2 warnings emitted +For more information about this error, try `rustc --explain E0759`. Future incompatibility report: Future breakage diagnostic: -error: `date_range` is ambiguous +error[E0759]: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); @@ -88,7 +89,7 @@ LL | use super::prelude::*; = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default Future breakage diagnostic: -error: `date_range` is ambiguous +error[E0759]: `date_range` is ambiguous --> $DIR/ambiguous-9.rs:23:5 | LL | date_range(); diff --git a/tests/ui/imports/duplicate.stderr b/tests/ui/imports/duplicate.stderr index 5cd3b0c2c8a55..2406b6c97bf93 100644 --- a/tests/ui/imports/duplicate.stderr +++ b/tests/ui/imports/duplicate.stderr @@ -8,7 +8,7 @@ LL | use crate::a::foo; | = note: `foo` must be defined only once in the value namespace of this module -error[E0659]: `foo` is ambiguous +error[E0759]: `foo` is ambiguous --> $DIR/duplicate.rs:48:15 | LL | use self::foo::bar; @@ -28,7 +28,7 @@ LL | use self::m2::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate -error[E0659]: `foo` is ambiguous +error[E0759]: `foo` is ambiguous --> $DIR/duplicate.rs:35:8 | LL | f::foo(); @@ -48,7 +48,7 @@ LL | pub use crate::b::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate -error[E0659]: `foo` is ambiguous +error[E0759]: `foo` is ambiguous --> $DIR/duplicate.rs:51:9 | LL | foo::bar(); @@ -68,7 +68,7 @@ LL | use self::m2::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate -error: `foo` is ambiguous +error[E0759]: `foo` is ambiguous --> $DIR/duplicate.rs:36:8 | LL | g::foo(); @@ -93,10 +93,10 @@ LL | pub use crate::b::*; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0252, E0659. +Some errors have detailed explanations: E0252, E0759. For more information about an error, try `rustc --explain E0252`. Future incompatibility report: Future breakage diagnostic: -error: `foo` is ambiguous +error[E0759]: `foo` is ambiguous --> $DIR/duplicate.rs:36:8 | LL | g::foo(); diff --git a/tests/ui/imports/unresolved-seg-after-ambiguous.stderr b/tests/ui/imports/unresolved-seg-after-ambiguous.stderr index 67316462a27e9..8342b7e62a88a 100644 --- a/tests/ui/imports/unresolved-seg-after-ambiguous.stderr +++ b/tests/ui/imports/unresolved-seg-after-ambiguous.stderr @@ -4,7 +4,7 @@ error[E0432]: unresolved import `self::a::E` LL | use self::a::E::in_exist; | ^ `E` is a struct, not a module -error: `E` is ambiguous +error[E0759]: `E` is ambiguous --> $DIR/unresolved-seg-after-ambiguous.rs:19:14 | LL | use self::a::E::in_exist; @@ -29,9 +29,10 @@ LL | pub use self::d::*; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0432`. +Some errors have detailed explanations: E0432, E0759. +For more information about an error, try `rustc --explain E0432`. Future incompatibility report: Future breakage diagnostic: -error: `E` is ambiguous +error[E0759]: `E` is ambiguous --> $DIR/unresolved-seg-after-ambiguous.rs:19:14 | LL | use self::a::E::in_exist; From c97e79fdc97733e84902407abb89822eb943149a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 12 Oct 2025 02:38:51 +0200 Subject: [PATCH 4/5] [WIP] [BROKEN] Move early buffered check-cfg lints to dyn lint diagnostics --- compiler/rustc_attr_parsing/messages.ftl | 44 +++ .../rustc_attr_parsing/src/attributes/cfg.rs | 21 +- .../src/attributes/cfg}/check_cfg.rs | 100 +++--- .../src/attributes/cfg_old.rs | 10 +- .../src/session_diagnostics.rs | 315 ++++++++++++++++++ compiler/rustc_lint/messages.ftl | 44 --- compiler/rustc_lint/src/early/diagnostics.rs | 10 +- compiler/rustc_lint/src/lints.rs | 315 ------------------ compiler/rustc_lint_defs/src/lib.rs | 2 - triagebot.toml | 2 +- 10 files changed, 434 insertions(+), 429 deletions(-) rename compiler/{rustc_lint/src/early/diagnostics => rustc_attr_parsing/src/attributes/cfg}/check_cfg.rs (81%) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 8b6b762f43102..88cf480d7afd5 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -217,6 +217,50 @@ attr_parsing_stability_outside_std = stability attributes may not be used outsid attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) +attr_parsing_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs` +attr_parsing_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead +attr_parsing_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} +attr_parsing_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}` +attr_parsing_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` + +attr_parsing_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` +attr_parsing_unexpected_cfg_doc_cargo = see for more information about checking conditional configuration +attr_parsing_unexpected_cfg_doc_rustc = see for more information about checking conditional configuration + +attr_parsing_unexpected_cfg_from_external_macro_origin = using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate +attr_parsing_unexpected_cfg_from_external_macro_refer = try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg +attr_parsing_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}` +attr_parsing_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more -> + [0] {""} + *[other] {" "}and {$and_more} more + } +attr_parsing_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities} +attr_parsing_unexpected_cfg_name_similar_name = there is a config with a similar name +attr_parsing_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values +attr_parsing_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value +attr_parsing_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value +attr_parsing_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")` +attr_parsing_unexpected_cfg_name_with_similar_value = found config with similar value + +attr_parsing_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value -> + [true] `{$value}` + *[false] (none) + } +attr_parsing_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml` +attr_parsing_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility -> + [true] {"(none), "} + *[false] {""} + }{$possibilities}{$and_more -> + [0] {""} + *[other] {" "}and {$and_more} more + } +attr_parsing_unexpected_cfg_value_no_expected_value = no expected value for `{$name}` +attr_parsing_unexpected_cfg_value_no_expected_values = no expected values for `{$name}` +attr_parsing_unexpected_cfg_value_remove_condition = remove the condition +attr_parsing_unexpected_cfg_value_remove_value = remove the value +attr_parsing_unexpected_cfg_value_similar_name = there is a expected value with a similar name +attr_parsing_unexpected_cfg_value_specify_value = specify a config value + attr_parsing_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 7085561107978..d43e54c3a36c3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -16,6 +16,9 @@ use crate::{ CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, }; +// NOTE: Crate-public since it's also used in sibling module `cfg_old`. +pub(crate) mod check_cfg; + pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute" @@ -234,35 +237,37 @@ pub fn eval_config_entry( EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } } - CfgEntry::NameValue { name, name_span, value, span } => { + &CfgEntry::NameValue { name, name_span, value, span } => { if let ShouldEmit::ErrorsAndLints = emit_lints { - match sess.psess.check_config.expecteds.get(name) { + match sess.psess.check_config.expecteds.get(&name) { Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => { id.emit_span_lint( sess, UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), + span, + // TODO: Do it lazily! Somehow pass a TyCtxt if possible + check_cfg::unexpected_cfg_value(sess, None, (name, name_span), value), ); } None if sess.psess.check_config.exhaustive_names => { id.emit_span_lint( sess, UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), + span, + // TODO: Do it lazily! Somehow pass a TyCtxt if possible + check_cfg::unexpected_cfg_name(sess, None, (name, name_span), value), ); } _ => { /* not unexpected */ } } } - if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) { + if sess.psess.config.contains(&(name, value.map(|(v, _)| v))) { EvalConfigResult::True } else { - EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: span } } } CfgEntry::Version(min_version, version_span) => { diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs similarity index 81% rename from compiler/rustc_lint/src/early/diagnostics/check_cfg.rs rename to compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs index e2f5dd315d570..b8eeab77acd34 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs @@ -1,12 +1,13 @@ use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::bug; -use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::ExpectedValues; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{ExpnKind, Ident, Span, Symbol, sym}; -use crate::lints; +use crate::{lints, session_diagnostics as diags}; + +// TODO: Temporary. +type TyCtxt<'tcx> = (); const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35; @@ -64,26 +65,27 @@ fn to_check_cfg_arg(name: Ident, value: Option, quotes: EscapeQuotes) -> fn cargo_help_sub( sess: &Session, inst: &impl Fn(EscapeQuotes) -> String, -) -> lints::UnexpectedCfgCargoHelp { +) -> diags::UnexpectedCfgCargoHelp { // We don't want to suggest the `build.rs` way to expected cfgs if we are already in a // `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is // `build_script_build`) to try to figure out if we are building a Cargo build script let unescaped = &inst(EscapeQuotes::No); + // TODO: Shouldn't this use the actual crate name? if matches!(&sess.opts.crate_name, Some(crate_name) if crate_name == "build_script_build") { - lints::UnexpectedCfgCargoHelp::lint_cfg(unescaped) + diags::UnexpectedCfgCargoHelp::lint_cfg(unescaped) } else { - lints::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes)) + diags::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes)) } } -fn rustc_macro_help(span: Span) -> Option { +fn rustc_macro_help(span: Span) -> Option { let oexpn = span.ctxt().outer_expn_data(); if let Some(def_id) = oexpn.macro_def_id && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind && def_id.krate != LOCAL_CRATE { - Some(lints::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name }) + Some(diags::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name }) } else { None } @@ -92,29 +94,31 @@ fn rustc_macro_help(span: Span) -> Option { fn cargo_macro_help( tcx: Option>, span: Span, -) -> Option { +) -> Option { let oexpn = span.ctxt().outer_expn_data(); if let Some(def_id) = oexpn.macro_def_id && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind && def_id.krate != LOCAL_CRATE - && let Some(tcx) = tcx + && let Some(_tcx) = tcx { - Some(lints::UnexpectedCfgCargoMacroHelp { + Some(diags::UnexpectedCfgCargoMacroHelp { macro_kind: macro_kind.descr(), macro_name, - crate_name: tcx.crate_name(def_id.krate), + // TODO: Rectify + // crate_name: tcx.crate_name(def_id.krate), + crate_name: sym::dummy, }) } else { None } } -pub(super) fn unexpected_cfg_name( +pub(crate) fn unexpected_cfg_name( sess: &Session, tcx: Option>, (name, name_span): (Symbol, Span), value: Option<(Symbol, Span)>, -) -> lints::UnexpectedCfgName { +) -> diags::UnexpectedCfgName { #[allow(rustc::potential_query_instability)] let possibilities: Vec = sess.psess.check_config.expecteds.keys().copied().collect(); @@ -139,12 +143,12 @@ pub(super) fn unexpected_cfg_name( let mut is_feature_cfg = name == sym::feature; let code_sugg = if is_feature_cfg && is_from_cargo { - lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures + diags::unexpected_cfg_name::CodeSuggestion::DefineFeatures // Suggest correct `version("..")` predicate syntax } else if let Some((_value, value_span)) = value && name == sym::version { - lints::unexpected_cfg_name::CodeSuggestion::VersionSyntax { + diags::unexpected_cfg_name::CodeSuggestion::VersionSyntax { between_name_and_value: name_span.between(value_span), after_value: value_span.shrink_to_hi(), } @@ -164,7 +168,7 @@ pub(super) fn unexpected_cfg_name( if !possibilities.is_empty() { let possibilities = possibilities.iter().copied().cloned().collect::>().into(); - Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities }) + Some(diags::unexpected_cfg_name::ExpectedValues { best_match, possibilities }) } else { None } @@ -173,37 +177,37 @@ pub(super) fn unexpected_cfg_name( let best_match = Ident::new(best_match, name_span); if let Some((value, value_span)) = value { if best_match_values.contains(&Some(value)) { - lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue { + diags::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue { span: name_span, code: best_match.to_string(), } } else if best_match_values.contains(&None) { - lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue { + diags::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue { span: name_span.to(value_span), code: best_match.to_string(), } } else if let Some(first_value) = possibilities.first() { - lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { + diags::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { span: name_span.to(value_span), code: format!("{best_match} = \"{first_value}\""), expected: get_possibilities_sub(), } } else { - lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { + diags::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { span: name_span.to(value_span), code: best_match.to_string(), expected: get_possibilities_sub(), } } } else { - lints::unexpected_cfg_name::CodeSuggestion::SimilarName { + diags::unexpected_cfg_name::CodeSuggestion::SimilarName { span: name_span, code: best_match.to_string(), expected: get_possibilities_sub(), } } } else { - lints::unexpected_cfg_name::CodeSuggestion::SimilarName { + diags::unexpected_cfg_name::CodeSuggestion::SimilarName { span: name_span, code: best_match.to_string(), expected: None, @@ -214,7 +218,7 @@ pub(super) fn unexpected_cfg_name( names_possibilities.sort(); names_possibilities .iter() - .map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue { + .map(|cfg_name| diags::unexpected_cfg_name::FoundWithSimilarValue { span: name_span, code: format!("{cfg_name} = \"{name}\""), }) @@ -228,14 +232,14 @@ pub(super) fn unexpected_cfg_name( let expected_names = if !possibilities.is_empty() { let possibilities: Vec<_> = possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect(); - Some(lints::unexpected_cfg_name::ExpectedNames { + Some(diags::unexpected_cfg_name::ExpectedNames { possibilities: possibilities.into(), and_more, }) } else { None }; - lints::unexpected_cfg_name::CodeSuggestion::SimilarValues { + diags::unexpected_cfg_name::CodeSuggestion::SimilarValues { with_similar_values: similar_values, expected_names, } @@ -251,29 +255,29 @@ pub(super) fn unexpected_cfg_name( } else { None }; - lints::unexpected_cfg_name::InvocationHelp::Cargo { + diags::unexpected_cfg_name::InvocationHelp::Cargo { help, macro_help: cargo_macro_help(tcx, name_span), } } else { - let help = lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)); - lints::unexpected_cfg_name::InvocationHelp::Rustc { + let help = diags::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)); + diags::unexpected_cfg_name::InvocationHelp::Rustc { help, macro_help: rustc_macro_help(name_span), } }; - lints::UnexpectedCfgName { code_sugg, invocation_help, name } + diags::UnexpectedCfgName { code_sugg, invocation_help, name } } -pub(super) fn unexpected_cfg_value( +pub(crate) fn unexpected_cfg_value( sess: &Session, tcx: Option>, (name, name_span): (Symbol, Span), value: Option<(Symbol, Span)>, -) -> lints::UnexpectedCfgValue { +) -> diags::UnexpectedCfgValue { let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else { - bug!( + panic!( "it shouldn't be possible to have a diagnostic on a value whose name is not in values" ); }; @@ -300,7 +304,7 @@ pub(super) fn unexpected_cfg_value( possibilities.clone(), FilterWellKnownNames::No, ); - lints::unexpected_cfg_value::ExpectedValues { + diags::unexpected_cfg_value::ExpectedValues { name, have_none_possibility, possibilities: possibilities.into(), @@ -311,7 +315,7 @@ pub(super) fn unexpected_cfg_value( let suggestion = if let Some((value, value_span)) = value { // Suggest the most probable if we found one if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) { - Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName { + Some(diags::unexpected_cfg_value::ChangeValueSuggestion::SimilarName { span: value_span, best_match, }) @@ -319,7 +323,7 @@ pub(super) fn unexpected_cfg_value( None } } else if let &[first_possibility] = &possibilities[..] { - Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue { + Some(diags::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue { span: name_span.shrink_to_hi(), first_possibility, }) @@ -327,21 +331,21 @@ pub(super) fn unexpected_cfg_value( None }; - lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion } + diags::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion } } else if have_none_possibility { let suggestion = - value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion { + value.map(|(_value, value_span)| diags::unexpected_cfg_value::RemoveValueSuggestion { span: name_span.shrink_to_hi().to(value_span), }); - lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name } + diags::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name } } else { let span = if let Some((_value, value_span)) = value { name_span.to(value_span) } else { name_span }; - let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span }; - lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name } + let suggestion = diags::unexpected_cfg_value::RemoveConditionSuggestion { span }; + diags::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name } }; // We don't want to encourage people to add values to a well-known names, as these are @@ -362,32 +366,32 @@ pub(super) fn unexpected_cfg_value( let invocation_help = if is_from_cargo { let help = if name == sym::feature && !is_from_external_macro { if let Some((value, _value_span)) = value { - Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value }) + Some(diags::unexpected_cfg_value::CargoHelp::AddFeature { value }) } else { - Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures) + Some(diags::unexpected_cfg_value::CargoHelp::DefineFeatures) } } else if can_suggest_adding_value && !is_from_external_macro { - Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst))) + Some(diags::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst))) } else { None }; - lints::unexpected_cfg_value::InvocationHelp::Cargo { + diags::unexpected_cfg_value::InvocationHelp::Cargo { help, macro_help: cargo_macro_help(tcx, name_span), } } else { let help = if can_suggest_adding_value { - Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No))) + Some(diags::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No))) } else { None }; - lints::unexpected_cfg_value::InvocationHelp::Rustc { + diags::unexpected_cfg_value::InvocationHelp::Rustc { help, macro_help: rustc_macro_help(name_span), } }; - lints::UnexpectedCfgValue { + diags::UnexpectedCfgValue { code_sugg, invocation_help, has_value: value.is_some(), diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index 3257d898eccbc..783a5c355e793 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -51,7 +51,10 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - BuiltinLintDiag::UnexpectedCfgValue( + // TODO: Do it lazily! Somehow pass a TyCtxt if possible + super::cfg::check_cfg::unexpected_cfg_value( + sess, + None, (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), ), @@ -62,7 +65,10 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - BuiltinLintDiag::UnexpectedCfgName( + // TODO: Do it lazily! Somehow pass a TyCtxt if possible + super::cfg::check_cfg::unexpected_cfg_name( + sess, + None, (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), ), diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 1194ac5872cb2..cc941f467a3a4 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -971,3 +971,318 @@ pub(crate) struct LimitInvalid<'a> { pub value_span: Span, pub error_str: &'a str, } + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_unexpected_cfg_name)] +pub(crate) struct UnexpectedCfgName { + #[subdiagnostic] + pub code_sugg: unexpected_cfg_name::CodeSuggestion, + #[subdiagnostic] + pub invocation_help: unexpected_cfg_name::InvocationHelp, + + pub name: Symbol, +} + +pub(crate) mod unexpected_cfg_name { + use rustc_errors::DiagSymbolList; + use rustc_macros::Subdiagnostic; + use rustc_span::{Ident, Span, Symbol}; + + #[derive(Subdiagnostic)] + pub(crate) enum CodeSuggestion { + #[help(attr_parsing_unexpected_cfg_define_features)] + DefineFeatures, + #[multipart_suggestion( + attr_parsing_unexpected_cfg_name_version_syntax, + applicability = "machine-applicable" + )] + VersionSyntax { + #[suggestion_part(code = "(")] + between_name_and_value: Span, + #[suggestion_part(code = ")")] + after_value: Span, + }, + #[suggestion( + attr_parsing_unexpected_cfg_name_similar_name_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameAndValue { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + attr_parsing_unexpected_cfg_name_similar_name_no_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameNoValue { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + attr_parsing_unexpected_cfg_name_similar_name_different_values, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameDifferentValues { + #[primary_span] + span: Span, + code: String, + #[subdiagnostic] + expected: Option, + }, + #[suggestion( + attr_parsing_unexpected_cfg_name_similar_name, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarName { + #[primary_span] + span: Span, + code: String, + #[subdiagnostic] + expected: Option, + }, + SimilarValues { + #[subdiagnostic] + with_similar_values: Vec, + #[subdiagnostic] + expected_names: Option, + }, + } + + #[derive(Subdiagnostic)] + #[help(attr_parsing_unexpected_cfg_name_expected_values)] + pub(crate) struct ExpectedValues { + pub best_match: Symbol, + pub possibilities: DiagSymbolList, + } + + #[derive(Subdiagnostic)] + #[suggestion( + attr_parsing_unexpected_cfg_name_with_similar_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + pub(crate) struct FoundWithSimilarValue { + #[primary_span] + pub span: Span, + pub code: String, + } + + #[derive(Subdiagnostic)] + #[help_once(attr_parsing_unexpected_cfg_name_expected_names)] + pub(crate) struct ExpectedNames { + pub possibilities: DiagSymbolList, + pub and_more: usize, + } + + #[derive(Subdiagnostic)] + pub(crate) enum InvocationHelp { + #[note(attr_parsing_unexpected_cfg_doc_cargo)] + Cargo { + #[subdiagnostic] + macro_help: Option, + #[subdiagnostic] + help: Option, + }, + #[note(attr_parsing_unexpected_cfg_doc_rustc)] + Rustc { + #[subdiagnostic] + macro_help: Option, + #[subdiagnostic] + help: super::UnexpectedCfgRustcHelp, + }, + } +} + +#[derive(LintDiagnostic)] +#[diag(attr_parsing_unexpected_cfg_value)] +pub(crate) struct UnexpectedCfgValue { + #[subdiagnostic] + pub code_sugg: unexpected_cfg_value::CodeSuggestion, + #[subdiagnostic] + pub invocation_help: unexpected_cfg_value::InvocationHelp, + + pub has_value: bool, + pub value: String, +} + +pub(crate) mod unexpected_cfg_value { + use rustc_errors::DiagSymbolList; + use rustc_macros::Subdiagnostic; + use rustc_span::{Span, Symbol}; + + #[derive(Subdiagnostic)] + pub(crate) enum CodeSuggestion { + ChangeValue { + #[subdiagnostic] + expected_values: ExpectedValues, + #[subdiagnostic] + suggestion: Option, + }, + #[note(attr_parsing_unexpected_cfg_value_no_expected_value)] + RemoveValue { + #[subdiagnostic] + suggestion: Option, + + name: Symbol, + }, + #[note(attr_parsing_unexpected_cfg_value_no_expected_values)] + RemoveCondition { + #[subdiagnostic] + suggestion: RemoveConditionSuggestion, + + name: Symbol, + }, + } + + #[derive(Subdiagnostic)] + pub(crate) enum ChangeValueSuggestion { + #[suggestion( + attr_parsing_unexpected_cfg_value_similar_name, + code = r#""{best_match}""#, + applicability = "maybe-incorrect" + )] + SimilarName { + #[primary_span] + span: Span, + best_match: Symbol, + }, + #[suggestion( + attr_parsing_unexpected_cfg_value_specify_value, + code = r#" = "{first_possibility}""#, + applicability = "maybe-incorrect" + )] + SpecifyValue { + #[primary_span] + span: Span, + first_possibility: Symbol, + }, + } + + #[derive(Subdiagnostic)] + #[suggestion( + attr_parsing_unexpected_cfg_value_remove_value, + code = "", + applicability = "maybe-incorrect" + )] + pub(crate) struct RemoveValueSuggestion { + #[primary_span] + pub span: Span, + } + + #[derive(Subdiagnostic)] + #[suggestion( + attr_parsing_unexpected_cfg_value_remove_condition, + code = "", + applicability = "maybe-incorrect" + )] + pub(crate) struct RemoveConditionSuggestion { + #[primary_span] + pub span: Span, + } + + #[derive(Subdiagnostic)] + #[note(attr_parsing_unexpected_cfg_value_expected_values)] + pub(crate) struct ExpectedValues { + pub name: Symbol, + pub have_none_possibility: bool, + pub possibilities: DiagSymbolList, + pub and_more: usize, + } + + #[derive(Subdiagnostic)] + pub(crate) enum InvocationHelp { + #[note(attr_parsing_unexpected_cfg_doc_cargo)] + Cargo { + #[subdiagnostic] + help: Option, + #[subdiagnostic] + macro_help: Option, + }, + #[note(attr_parsing_unexpected_cfg_doc_rustc)] + Rustc { + #[subdiagnostic] + help: Option, + #[subdiagnostic] + macro_help: Option, + }, + } + + #[derive(Subdiagnostic)] + pub(crate) enum CargoHelp { + #[help(attr_parsing_unexpected_cfg_value_add_feature)] + AddFeature { + value: Symbol, + }, + #[help(attr_parsing_unexpected_cfg_define_features)] + DefineFeatures, + Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp), + } +} + +#[derive(Subdiagnostic)] +pub(crate) enum UnexpectedCfgCargoHelp { + #[help(attr_parsing_unexpected_cfg_add_cargo_feature)] + #[help(attr_parsing_unexpected_cfg_add_cargo_toml_lint_cfg)] + LintCfg { cargo_toml_lint_cfg: String }, + #[help(attr_parsing_unexpected_cfg_add_cargo_feature)] + #[help(attr_parsing_unexpected_cfg_add_cargo_toml_lint_cfg)] + #[help(attr_parsing_unexpected_cfg_add_build_rs_println)] + LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String }, +} + +impl UnexpectedCfgCargoHelp { + fn cargo_toml_lint_cfg(unescaped: &str) -> String { + format!( + "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}" + ) + } + + pub(crate) fn attr_parsing_cfg(unescaped: &str) -> Self { + UnexpectedCfgCargoHelp::LintCfg { + cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), + } + } + + pub(crate) fn attr_parsing_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self { + UnexpectedCfgCargoHelp::LintCfgAndBuildRs { + cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), + build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"), + } + } +} + +#[derive(Subdiagnostic)] +#[help(attr_parsing_unexpected_cfg_add_cmdline_arg)] +pub(crate) struct UnexpectedCfgRustcHelp { + pub cmdline_arg: String, +} + +impl UnexpectedCfgRustcHelp { + pub(crate) fn new(unescaped: &str) -> Self { + Self { cmdline_arg: format!("--check-cfg={unescaped}") } + } +} + +#[derive(Subdiagnostic)] +#[note(attr_parsing_unexpected_cfg_from_external_macro_origin)] +#[help(attr_parsing_unexpected_cfg_from_external_macro_refer)] +pub(crate) struct UnexpectedCfgRustcMacroHelp { + pub macro_kind: &'static str, + pub macro_name: Symbol, +} + +#[derive(Subdiagnostic)] +#[note(attr_parsing_unexpected_cfg_from_external_macro_origin)] +#[help(attr_parsing_unexpected_cfg_from_external_macro_refer)] +#[help(attr_parsing_unexpected_cfg_cargo_update)] +pub(crate) struct UnexpectedCfgCargoMacroHelp { + pub macro_kind: &'static str, + pub macro_name: Symbol, + pub crate_name: Symbol, +} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 2b3f16d65c381..18a9c0382356d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -787,50 +787,6 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value -lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs` -lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead -lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} -lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}` -lint_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` - -lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` -lint_unexpected_cfg_doc_cargo = see for more information about checking conditional configuration -lint_unexpected_cfg_doc_rustc = see for more information about checking conditional configuration - -lint_unexpected_cfg_from_external_macro_origin = using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate -lint_unexpected_cfg_from_external_macro_refer = try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg -lint_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}` -lint_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more -> - [0] {""} - *[other] {" "}and {$and_more} more - } -lint_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities} -lint_unexpected_cfg_name_similar_name = there is a config with a similar name -lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values -lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value -lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value -lint_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")` -lint_unexpected_cfg_name_with_similar_value = found config with similar value - -lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value -> - [true] `{$value}` - *[false] (none) - } -lint_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml` -lint_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility -> - [true] {"(none), "} - *[false] {""} - }{$possibilities}{$and_more -> - [0] {""} - *[other] {" "}and {$and_more} more - } -lint_unexpected_cfg_value_no_expected_value = no expected value for `{$name}` -lint_unexpected_cfg_value_no_expected_values = no expected values for `{$name}` -lint_unexpected_cfg_value_remove_condition = remove the condition -lint_unexpected_cfg_value_remove_value = remove the value -lint_unexpected_cfg_value_similar_name = there is a expected value with a similar name -lint_unexpected_cfg_value_specify_value = specify a config value - lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op .label = this function will not propagate the caller location diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index e376d7d2ab883..9e148aaae8aa2 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -13,11 +13,9 @@ use tracing::debug; use crate::lints; -mod check_cfg; - pub fn decorate_builtin_lint( sess: &Session, - tcx: Option>, + _tcx: Option>, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>, ) { @@ -168,12 +166,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::UnexpectedCfgName(name, value) => { - check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag); - } - BuiltinLintDiag::UnexpectedCfgValue(name, value) => { - check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag); - } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index f99d3fc5e98e3..c92ef25ac435f 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2219,321 +2219,6 @@ pub(crate) enum InvalidAsmLabel { }, } -#[derive(Subdiagnostic)] -pub(crate) enum UnexpectedCfgCargoHelp { - #[help(lint_unexpected_cfg_add_cargo_feature)] - #[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)] - LintCfg { cargo_toml_lint_cfg: String }, - #[help(lint_unexpected_cfg_add_cargo_feature)] - #[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)] - #[help(lint_unexpected_cfg_add_build_rs_println)] - LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String }, -} - -impl UnexpectedCfgCargoHelp { - fn cargo_toml_lint_cfg(unescaped: &str) -> String { - format!( - "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}" - ) - } - - pub(crate) fn lint_cfg(unescaped: &str) -> Self { - UnexpectedCfgCargoHelp::LintCfg { - cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), - } - } - - pub(crate) fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self { - UnexpectedCfgCargoHelp::LintCfgAndBuildRs { - cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), - build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"), - } - } -} - -#[derive(Subdiagnostic)] -#[help(lint_unexpected_cfg_add_cmdline_arg)] -pub(crate) struct UnexpectedCfgRustcHelp { - pub cmdline_arg: String, -} - -impl UnexpectedCfgRustcHelp { - pub(crate) fn new(unescaped: &str) -> Self { - Self { cmdline_arg: format!("--check-cfg={unescaped}") } - } -} - -#[derive(Subdiagnostic)] -#[note(lint_unexpected_cfg_from_external_macro_origin)] -#[help(lint_unexpected_cfg_from_external_macro_refer)] -pub(crate) struct UnexpectedCfgRustcMacroHelp { - pub macro_kind: &'static str, - pub macro_name: Symbol, -} - -#[derive(Subdiagnostic)] -#[note(lint_unexpected_cfg_from_external_macro_origin)] -#[help(lint_unexpected_cfg_from_external_macro_refer)] -#[help(lint_unexpected_cfg_cargo_update)] -pub(crate) struct UnexpectedCfgCargoMacroHelp { - pub macro_kind: &'static str, - pub macro_name: Symbol, - pub crate_name: Symbol, -} - -#[derive(LintDiagnostic)] -#[diag(lint_unexpected_cfg_name)] -pub(crate) struct UnexpectedCfgName { - #[subdiagnostic] - pub code_sugg: unexpected_cfg_name::CodeSuggestion, - #[subdiagnostic] - pub invocation_help: unexpected_cfg_name::InvocationHelp, - - pub name: Symbol, -} - -pub(crate) mod unexpected_cfg_name { - use rustc_errors::DiagSymbolList; - use rustc_macros::Subdiagnostic; - use rustc_span::{Ident, Span, Symbol}; - - #[derive(Subdiagnostic)] - pub(crate) enum CodeSuggestion { - #[help(lint_unexpected_cfg_define_features)] - DefineFeatures, - #[multipart_suggestion( - lint_unexpected_cfg_name_version_syntax, - applicability = "machine-applicable" - )] - VersionSyntax { - #[suggestion_part(code = "(")] - between_name_and_value: Span, - #[suggestion_part(code = ")")] - after_value: Span, - }, - #[suggestion( - lint_unexpected_cfg_name_similar_name_value, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarNameAndValue { - #[primary_span] - span: Span, - code: String, - }, - #[suggestion( - lint_unexpected_cfg_name_similar_name_no_value, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarNameNoValue { - #[primary_span] - span: Span, - code: String, - }, - #[suggestion( - lint_unexpected_cfg_name_similar_name_different_values, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarNameDifferentValues { - #[primary_span] - span: Span, - code: String, - #[subdiagnostic] - expected: Option, - }, - #[suggestion( - lint_unexpected_cfg_name_similar_name, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarName { - #[primary_span] - span: Span, - code: String, - #[subdiagnostic] - expected: Option, - }, - SimilarValues { - #[subdiagnostic] - with_similar_values: Vec, - #[subdiagnostic] - expected_names: Option, - }, - } - - #[derive(Subdiagnostic)] - #[help(lint_unexpected_cfg_name_expected_values)] - pub(crate) struct ExpectedValues { - pub best_match: Symbol, - pub possibilities: DiagSymbolList, - } - - #[derive(Subdiagnostic)] - #[suggestion( - lint_unexpected_cfg_name_with_similar_value, - applicability = "maybe-incorrect", - code = "{code}" - )] - pub(crate) struct FoundWithSimilarValue { - #[primary_span] - pub span: Span, - pub code: String, - } - - #[derive(Subdiagnostic)] - #[help_once(lint_unexpected_cfg_name_expected_names)] - pub(crate) struct ExpectedNames { - pub possibilities: DiagSymbolList, - pub and_more: usize, - } - - #[derive(Subdiagnostic)] - pub(crate) enum InvocationHelp { - #[note(lint_unexpected_cfg_doc_cargo)] - Cargo { - #[subdiagnostic] - macro_help: Option, - #[subdiagnostic] - help: Option, - }, - #[note(lint_unexpected_cfg_doc_rustc)] - Rustc { - #[subdiagnostic] - macro_help: Option, - #[subdiagnostic] - help: super::UnexpectedCfgRustcHelp, - }, - } -} - -#[derive(LintDiagnostic)] -#[diag(lint_unexpected_cfg_value)] -pub(crate) struct UnexpectedCfgValue { - #[subdiagnostic] - pub code_sugg: unexpected_cfg_value::CodeSuggestion, - #[subdiagnostic] - pub invocation_help: unexpected_cfg_value::InvocationHelp, - - pub has_value: bool, - pub value: String, -} - -pub(crate) mod unexpected_cfg_value { - use rustc_errors::DiagSymbolList; - use rustc_macros::Subdiagnostic; - use rustc_span::{Span, Symbol}; - - #[derive(Subdiagnostic)] - pub(crate) enum CodeSuggestion { - ChangeValue { - #[subdiagnostic] - expected_values: ExpectedValues, - #[subdiagnostic] - suggestion: Option, - }, - #[note(lint_unexpected_cfg_value_no_expected_value)] - RemoveValue { - #[subdiagnostic] - suggestion: Option, - - name: Symbol, - }, - #[note(lint_unexpected_cfg_value_no_expected_values)] - RemoveCondition { - #[subdiagnostic] - suggestion: RemoveConditionSuggestion, - - name: Symbol, - }, - } - - #[derive(Subdiagnostic)] - pub(crate) enum ChangeValueSuggestion { - #[suggestion( - lint_unexpected_cfg_value_similar_name, - code = r#""{best_match}""#, - applicability = "maybe-incorrect" - )] - SimilarName { - #[primary_span] - span: Span, - best_match: Symbol, - }, - #[suggestion( - lint_unexpected_cfg_value_specify_value, - code = r#" = "{first_possibility}""#, - applicability = "maybe-incorrect" - )] - SpecifyValue { - #[primary_span] - span: Span, - first_possibility: Symbol, - }, - } - - #[derive(Subdiagnostic)] - #[suggestion( - lint_unexpected_cfg_value_remove_value, - code = "", - applicability = "maybe-incorrect" - )] - pub(crate) struct RemoveValueSuggestion { - #[primary_span] - pub span: Span, - } - - #[derive(Subdiagnostic)] - #[suggestion( - lint_unexpected_cfg_value_remove_condition, - code = "", - applicability = "maybe-incorrect" - )] - pub(crate) struct RemoveConditionSuggestion { - #[primary_span] - pub span: Span, - } - - #[derive(Subdiagnostic)] - #[note(lint_unexpected_cfg_value_expected_values)] - pub(crate) struct ExpectedValues { - pub name: Symbol, - pub have_none_possibility: bool, - pub possibilities: DiagSymbolList, - pub and_more: usize, - } - - #[derive(Subdiagnostic)] - pub(crate) enum InvocationHelp { - #[note(lint_unexpected_cfg_doc_cargo)] - Cargo { - #[subdiagnostic] - help: Option, - #[subdiagnostic] - macro_help: Option, - }, - #[note(lint_unexpected_cfg_doc_rustc)] - Rustc { - #[subdiagnostic] - help: Option, - #[subdiagnostic] - macro_help: Option, - }, - } - - #[derive(Subdiagnostic)] - pub(crate) enum CargoHelp { - #[help(lint_unexpected_cfg_value_add_feature)] - AddFeature { - value: Symbol, - }, - #[help(lint_unexpected_cfg_define_features)] - DefineFeatures, - Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp), - } -} - #[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] #[help] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 0ddc2e3076e92..87834de19cb81 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -636,8 +636,6 @@ pub enum BuiltinLintDiag { }, BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), - UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), - UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), SingleUseLifetime { /// Span of the parameter which declares this lifetime. diff --git a/triagebot.toml b/triagebot.toml index 79b5c2d1b7238..4cb107eb08bd2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -956,7 +956,7 @@ cc = ["@Nadrieril"] message = "Some changes occurred in cfg and check-cfg configuration" cc = ["@Urgau"] -[mentions."compiler/rustc_lint/src/early/diagnostics/check_cfg.rs"] +[mentions."compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs"] message = "Some changes occurred in check-cfg diagnostics" cc = ["@Urgau"] From a944814aa7f781877d0d4449ec38e3ac73c93673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 13 Oct 2025 14:03:58 +0200 Subject: [PATCH 5/5] Revert "[WIP] [BROKEN] Move early buffered check-cfg lints to dyn lint diagnostics" This reverts commit c97e79fdc97733e84902407abb89822eb943149a. --- compiler/rustc_attr_parsing/messages.ftl | 44 --- .../rustc_attr_parsing/src/attributes/cfg.rs | 21 +- .../src/attributes/cfg_old.rs | 10 +- .../src/session_diagnostics.rs | 315 ------------------ compiler/rustc_lint/messages.ftl | 44 +++ compiler/rustc_lint/src/early/diagnostics.rs | 10 +- .../src/early/diagnostics}/check_cfg.rs | 100 +++--- compiler/rustc_lint/src/lints.rs | 315 ++++++++++++++++++ compiler/rustc_lint_defs/src/lib.rs | 2 + triagebot.toml | 2 +- 10 files changed, 429 insertions(+), 434 deletions(-) rename compiler/{rustc_attr_parsing/src/attributes/cfg => rustc_lint/src/early/diagnostics}/check_cfg.rs (81%) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 88cf480d7afd5..8b6b762f43102 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -217,50 +217,6 @@ attr_parsing_stability_outside_std = stability attributes may not be used outsid attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -attr_parsing_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs` -attr_parsing_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead -attr_parsing_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} -attr_parsing_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}` -attr_parsing_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` - -attr_parsing_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` -attr_parsing_unexpected_cfg_doc_cargo = see for more information about checking conditional configuration -attr_parsing_unexpected_cfg_doc_rustc = see for more information about checking conditional configuration - -attr_parsing_unexpected_cfg_from_external_macro_origin = using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate -attr_parsing_unexpected_cfg_from_external_macro_refer = try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg -attr_parsing_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}` -attr_parsing_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more -> - [0] {""} - *[other] {" "}and {$and_more} more - } -attr_parsing_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities} -attr_parsing_unexpected_cfg_name_similar_name = there is a config with a similar name -attr_parsing_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values -attr_parsing_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value -attr_parsing_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value -attr_parsing_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")` -attr_parsing_unexpected_cfg_name_with_similar_value = found config with similar value - -attr_parsing_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value -> - [true] `{$value}` - *[false] (none) - } -attr_parsing_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml` -attr_parsing_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility -> - [true] {"(none), "} - *[false] {""} - }{$possibilities}{$and_more -> - [0] {""} - *[other] {" "}and {$and_more} more - } -attr_parsing_unexpected_cfg_value_no_expected_value = no expected value for `{$name}` -attr_parsing_unexpected_cfg_value_no_expected_values = no expected values for `{$name}` -attr_parsing_unexpected_cfg_value_remove_condition = remove the condition -attr_parsing_unexpected_cfg_value_remove_value = remove the value -attr_parsing_unexpected_cfg_value_similar_name = there is a expected value with a similar name -attr_parsing_unexpected_cfg_value_specify_value = specify a config value - attr_parsing_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index d43e54c3a36c3..7085561107978 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -16,9 +16,6 @@ use crate::{ CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, }; -// NOTE: Crate-public since it's also used in sibling module `cfg_old`. -pub(crate) mod check_cfg; - pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute" @@ -237,37 +234,35 @@ pub fn eval_config_entry( EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } } - &CfgEntry::NameValue { name, name_span, value, span } => { + CfgEntry::NameValue { name, name_span, value, span } => { if let ShouldEmit::ErrorsAndLints = emit_lints { - match sess.psess.check_config.expecteds.get(&name) { + match sess.psess.check_config.expecteds.get(name) { Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => { id.emit_span_lint( sess, UNEXPECTED_CFGS, - span, - // TODO: Do it lazily! Somehow pass a TyCtxt if possible - check_cfg::unexpected_cfg_value(sess, None, (name, name_span), value), + *span, + BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), ); } None if sess.psess.check_config.exhaustive_names => { id.emit_span_lint( sess, UNEXPECTED_CFGS, - span, - // TODO: Do it lazily! Somehow pass a TyCtxt if possible - check_cfg::unexpected_cfg_name(sess, None, (name, name_span), value), + *span, + BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), ); } _ => { /* not unexpected */ } } } - if sess.psess.config.contains(&(name, value.map(|(v, _)| v))) { + if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) { EvalConfigResult::True } else { - EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: span } + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } } CfgEntry::Version(min_version, version_span) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index 783a5c355e793..3257d898eccbc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -51,10 +51,7 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - // TODO: Do it lazily! Somehow pass a TyCtxt if possible - super::cfg::check_cfg::unexpected_cfg_value( - sess, - None, + BuiltinLintDiag::UnexpectedCfgValue( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), ), @@ -65,10 +62,7 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - // TODO: Do it lazily! Somehow pass a TyCtxt if possible - super::cfg::check_cfg::unexpected_cfg_name( - sess, - None, + BuiltinLintDiag::UnexpectedCfgName( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), ), diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index cc941f467a3a4..1194ac5872cb2 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -971,318 +971,3 @@ pub(crate) struct LimitInvalid<'a> { pub value_span: Span, pub error_str: &'a str, } - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_unexpected_cfg_name)] -pub(crate) struct UnexpectedCfgName { - #[subdiagnostic] - pub code_sugg: unexpected_cfg_name::CodeSuggestion, - #[subdiagnostic] - pub invocation_help: unexpected_cfg_name::InvocationHelp, - - pub name: Symbol, -} - -pub(crate) mod unexpected_cfg_name { - use rustc_errors::DiagSymbolList; - use rustc_macros::Subdiagnostic; - use rustc_span::{Ident, Span, Symbol}; - - #[derive(Subdiagnostic)] - pub(crate) enum CodeSuggestion { - #[help(attr_parsing_unexpected_cfg_define_features)] - DefineFeatures, - #[multipart_suggestion( - attr_parsing_unexpected_cfg_name_version_syntax, - applicability = "machine-applicable" - )] - VersionSyntax { - #[suggestion_part(code = "(")] - between_name_and_value: Span, - #[suggestion_part(code = ")")] - after_value: Span, - }, - #[suggestion( - attr_parsing_unexpected_cfg_name_similar_name_value, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarNameAndValue { - #[primary_span] - span: Span, - code: String, - }, - #[suggestion( - attr_parsing_unexpected_cfg_name_similar_name_no_value, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarNameNoValue { - #[primary_span] - span: Span, - code: String, - }, - #[suggestion( - attr_parsing_unexpected_cfg_name_similar_name_different_values, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarNameDifferentValues { - #[primary_span] - span: Span, - code: String, - #[subdiagnostic] - expected: Option, - }, - #[suggestion( - attr_parsing_unexpected_cfg_name_similar_name, - applicability = "maybe-incorrect", - code = "{code}" - )] - SimilarName { - #[primary_span] - span: Span, - code: String, - #[subdiagnostic] - expected: Option, - }, - SimilarValues { - #[subdiagnostic] - with_similar_values: Vec, - #[subdiagnostic] - expected_names: Option, - }, - } - - #[derive(Subdiagnostic)] - #[help(attr_parsing_unexpected_cfg_name_expected_values)] - pub(crate) struct ExpectedValues { - pub best_match: Symbol, - pub possibilities: DiagSymbolList, - } - - #[derive(Subdiagnostic)] - #[suggestion( - attr_parsing_unexpected_cfg_name_with_similar_value, - applicability = "maybe-incorrect", - code = "{code}" - )] - pub(crate) struct FoundWithSimilarValue { - #[primary_span] - pub span: Span, - pub code: String, - } - - #[derive(Subdiagnostic)] - #[help_once(attr_parsing_unexpected_cfg_name_expected_names)] - pub(crate) struct ExpectedNames { - pub possibilities: DiagSymbolList, - pub and_more: usize, - } - - #[derive(Subdiagnostic)] - pub(crate) enum InvocationHelp { - #[note(attr_parsing_unexpected_cfg_doc_cargo)] - Cargo { - #[subdiagnostic] - macro_help: Option, - #[subdiagnostic] - help: Option, - }, - #[note(attr_parsing_unexpected_cfg_doc_rustc)] - Rustc { - #[subdiagnostic] - macro_help: Option, - #[subdiagnostic] - help: super::UnexpectedCfgRustcHelp, - }, - } -} - -#[derive(LintDiagnostic)] -#[diag(attr_parsing_unexpected_cfg_value)] -pub(crate) struct UnexpectedCfgValue { - #[subdiagnostic] - pub code_sugg: unexpected_cfg_value::CodeSuggestion, - #[subdiagnostic] - pub invocation_help: unexpected_cfg_value::InvocationHelp, - - pub has_value: bool, - pub value: String, -} - -pub(crate) mod unexpected_cfg_value { - use rustc_errors::DiagSymbolList; - use rustc_macros::Subdiagnostic; - use rustc_span::{Span, Symbol}; - - #[derive(Subdiagnostic)] - pub(crate) enum CodeSuggestion { - ChangeValue { - #[subdiagnostic] - expected_values: ExpectedValues, - #[subdiagnostic] - suggestion: Option, - }, - #[note(attr_parsing_unexpected_cfg_value_no_expected_value)] - RemoveValue { - #[subdiagnostic] - suggestion: Option, - - name: Symbol, - }, - #[note(attr_parsing_unexpected_cfg_value_no_expected_values)] - RemoveCondition { - #[subdiagnostic] - suggestion: RemoveConditionSuggestion, - - name: Symbol, - }, - } - - #[derive(Subdiagnostic)] - pub(crate) enum ChangeValueSuggestion { - #[suggestion( - attr_parsing_unexpected_cfg_value_similar_name, - code = r#""{best_match}""#, - applicability = "maybe-incorrect" - )] - SimilarName { - #[primary_span] - span: Span, - best_match: Symbol, - }, - #[suggestion( - attr_parsing_unexpected_cfg_value_specify_value, - code = r#" = "{first_possibility}""#, - applicability = "maybe-incorrect" - )] - SpecifyValue { - #[primary_span] - span: Span, - first_possibility: Symbol, - }, - } - - #[derive(Subdiagnostic)] - #[suggestion( - attr_parsing_unexpected_cfg_value_remove_value, - code = "", - applicability = "maybe-incorrect" - )] - pub(crate) struct RemoveValueSuggestion { - #[primary_span] - pub span: Span, - } - - #[derive(Subdiagnostic)] - #[suggestion( - attr_parsing_unexpected_cfg_value_remove_condition, - code = "", - applicability = "maybe-incorrect" - )] - pub(crate) struct RemoveConditionSuggestion { - #[primary_span] - pub span: Span, - } - - #[derive(Subdiagnostic)] - #[note(attr_parsing_unexpected_cfg_value_expected_values)] - pub(crate) struct ExpectedValues { - pub name: Symbol, - pub have_none_possibility: bool, - pub possibilities: DiagSymbolList, - pub and_more: usize, - } - - #[derive(Subdiagnostic)] - pub(crate) enum InvocationHelp { - #[note(attr_parsing_unexpected_cfg_doc_cargo)] - Cargo { - #[subdiagnostic] - help: Option, - #[subdiagnostic] - macro_help: Option, - }, - #[note(attr_parsing_unexpected_cfg_doc_rustc)] - Rustc { - #[subdiagnostic] - help: Option, - #[subdiagnostic] - macro_help: Option, - }, - } - - #[derive(Subdiagnostic)] - pub(crate) enum CargoHelp { - #[help(attr_parsing_unexpected_cfg_value_add_feature)] - AddFeature { - value: Symbol, - }, - #[help(attr_parsing_unexpected_cfg_define_features)] - DefineFeatures, - Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp), - } -} - -#[derive(Subdiagnostic)] -pub(crate) enum UnexpectedCfgCargoHelp { - #[help(attr_parsing_unexpected_cfg_add_cargo_feature)] - #[help(attr_parsing_unexpected_cfg_add_cargo_toml_lint_cfg)] - LintCfg { cargo_toml_lint_cfg: String }, - #[help(attr_parsing_unexpected_cfg_add_cargo_feature)] - #[help(attr_parsing_unexpected_cfg_add_cargo_toml_lint_cfg)] - #[help(attr_parsing_unexpected_cfg_add_build_rs_println)] - LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String }, -} - -impl UnexpectedCfgCargoHelp { - fn cargo_toml_lint_cfg(unescaped: &str) -> String { - format!( - "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}" - ) - } - - pub(crate) fn attr_parsing_cfg(unescaped: &str) -> Self { - UnexpectedCfgCargoHelp::LintCfg { - cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), - } - } - - pub(crate) fn attr_parsing_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self { - UnexpectedCfgCargoHelp::LintCfgAndBuildRs { - cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), - build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"), - } - } -} - -#[derive(Subdiagnostic)] -#[help(attr_parsing_unexpected_cfg_add_cmdline_arg)] -pub(crate) struct UnexpectedCfgRustcHelp { - pub cmdline_arg: String, -} - -impl UnexpectedCfgRustcHelp { - pub(crate) fn new(unescaped: &str) -> Self { - Self { cmdline_arg: format!("--check-cfg={unescaped}") } - } -} - -#[derive(Subdiagnostic)] -#[note(attr_parsing_unexpected_cfg_from_external_macro_origin)] -#[help(attr_parsing_unexpected_cfg_from_external_macro_refer)] -pub(crate) struct UnexpectedCfgRustcMacroHelp { - pub macro_kind: &'static str, - pub macro_name: Symbol, -} - -#[derive(Subdiagnostic)] -#[note(attr_parsing_unexpected_cfg_from_external_macro_origin)] -#[help(attr_parsing_unexpected_cfg_from_external_macro_refer)] -#[help(attr_parsing_unexpected_cfg_cargo_update)] -pub(crate) struct UnexpectedCfgCargoMacroHelp { - pub macro_kind: &'static str, - pub macro_name: Symbol, - pub crate_name: Symbol, -} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 18a9c0382356d..2b3f16d65c381 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -787,6 +787,50 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value +lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs` +lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead +lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} +lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}` +lint_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` + +lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml` +lint_unexpected_cfg_doc_cargo = see for more information about checking conditional configuration +lint_unexpected_cfg_doc_rustc = see for more information about checking conditional configuration + +lint_unexpected_cfg_from_external_macro_origin = using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate +lint_unexpected_cfg_from_external_macro_refer = try referring to `{$macro_name}` crate for guidance on how handle this unexpected cfg +lint_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}` +lint_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more -> + [0] {""} + *[other] {" "}and {$and_more} more + } +lint_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities} +lint_unexpected_cfg_name_similar_name = there is a config with a similar name +lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values +lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value +lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value +lint_unexpected_cfg_name_version_syntax = there is a similar config predicate: `version("..")` +lint_unexpected_cfg_name_with_similar_value = found config with similar value + +lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value -> + [true] `{$value}` + *[false] (none) + } +lint_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml` +lint_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility -> + [true] {"(none), "} + *[false] {""} + }{$possibilities}{$and_more -> + [0] {""} + *[other] {" "}and {$and_more} more + } +lint_unexpected_cfg_value_no_expected_value = no expected value for `{$name}` +lint_unexpected_cfg_value_no_expected_values = no expected values for `{$name}` +lint_unexpected_cfg_value_remove_condition = remove the condition +lint_unexpected_cfg_value_remove_value = remove the value +lint_unexpected_cfg_value_similar_name = there is a expected value with a similar name +lint_unexpected_cfg_value_specify_value = specify a config value + lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op .label = this function will not propagate the caller location diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 9e148aaae8aa2..e376d7d2ab883 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -13,9 +13,11 @@ use tracing::debug; use crate::lints; +mod check_cfg; + pub fn decorate_builtin_lint( sess: &Session, - _tcx: Option>, + tcx: Option>, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>, ) { @@ -166,6 +168,12 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } + BuiltinLintDiag::UnexpectedCfgName(name, value) => { + check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag); + } + BuiltinLintDiag::UnexpectedCfgValue(name, value) => { + check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag); + } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs similarity index 81% rename from compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs rename to compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index b8eeab77acd34..e2f5dd315d570 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -1,13 +1,12 @@ use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::bug; +use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::ExpectedValues; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{ExpnKind, Ident, Span, Symbol, sym}; -use crate::{lints, session_diagnostics as diags}; - -// TODO: Temporary. -type TyCtxt<'tcx> = (); +use crate::lints; const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35; @@ -65,27 +64,26 @@ fn to_check_cfg_arg(name: Ident, value: Option, quotes: EscapeQuotes) -> fn cargo_help_sub( sess: &Session, inst: &impl Fn(EscapeQuotes) -> String, -) -> diags::UnexpectedCfgCargoHelp { +) -> lints::UnexpectedCfgCargoHelp { // We don't want to suggest the `build.rs` way to expected cfgs if we are already in a // `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is // `build_script_build`) to try to figure out if we are building a Cargo build script let unescaped = &inst(EscapeQuotes::No); - // TODO: Shouldn't this use the actual crate name? if matches!(&sess.opts.crate_name, Some(crate_name) if crate_name == "build_script_build") { - diags::UnexpectedCfgCargoHelp::lint_cfg(unescaped) + lints::UnexpectedCfgCargoHelp::lint_cfg(unescaped) } else { - diags::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes)) + lints::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes)) } } -fn rustc_macro_help(span: Span) -> Option { +fn rustc_macro_help(span: Span) -> Option { let oexpn = span.ctxt().outer_expn_data(); if let Some(def_id) = oexpn.macro_def_id && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind && def_id.krate != LOCAL_CRATE { - Some(diags::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name }) + Some(lints::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name }) } else { None } @@ -94,31 +92,29 @@ fn rustc_macro_help(span: Span) -> Option { fn cargo_macro_help( tcx: Option>, span: Span, -) -> Option { +) -> Option { let oexpn = span.ctxt().outer_expn_data(); if let Some(def_id) = oexpn.macro_def_id && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind && def_id.krate != LOCAL_CRATE - && let Some(_tcx) = tcx + && let Some(tcx) = tcx { - Some(diags::UnexpectedCfgCargoMacroHelp { + Some(lints::UnexpectedCfgCargoMacroHelp { macro_kind: macro_kind.descr(), macro_name, - // TODO: Rectify - // crate_name: tcx.crate_name(def_id.krate), - crate_name: sym::dummy, + crate_name: tcx.crate_name(def_id.krate), }) } else { None } } -pub(crate) fn unexpected_cfg_name( +pub(super) fn unexpected_cfg_name( sess: &Session, tcx: Option>, (name, name_span): (Symbol, Span), value: Option<(Symbol, Span)>, -) -> diags::UnexpectedCfgName { +) -> lints::UnexpectedCfgName { #[allow(rustc::potential_query_instability)] let possibilities: Vec = sess.psess.check_config.expecteds.keys().copied().collect(); @@ -143,12 +139,12 @@ pub(crate) fn unexpected_cfg_name( let mut is_feature_cfg = name == sym::feature; let code_sugg = if is_feature_cfg && is_from_cargo { - diags::unexpected_cfg_name::CodeSuggestion::DefineFeatures + lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures // Suggest correct `version("..")` predicate syntax } else if let Some((_value, value_span)) = value && name == sym::version { - diags::unexpected_cfg_name::CodeSuggestion::VersionSyntax { + lints::unexpected_cfg_name::CodeSuggestion::VersionSyntax { between_name_and_value: name_span.between(value_span), after_value: value_span.shrink_to_hi(), } @@ -168,7 +164,7 @@ pub(crate) fn unexpected_cfg_name( if !possibilities.is_empty() { let possibilities = possibilities.iter().copied().cloned().collect::>().into(); - Some(diags::unexpected_cfg_name::ExpectedValues { best_match, possibilities }) + Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities }) } else { None } @@ -177,37 +173,37 @@ pub(crate) fn unexpected_cfg_name( let best_match = Ident::new(best_match, name_span); if let Some((value, value_span)) = value { if best_match_values.contains(&Some(value)) { - diags::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue { + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue { span: name_span, code: best_match.to_string(), } } else if best_match_values.contains(&None) { - diags::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue { + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue { span: name_span.to(value_span), code: best_match.to_string(), } } else if let Some(first_value) = possibilities.first() { - diags::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { span: name_span.to(value_span), code: format!("{best_match} = \"{first_value}\""), expected: get_possibilities_sub(), } } else { - diags::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { + lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues { span: name_span.to(value_span), code: best_match.to_string(), expected: get_possibilities_sub(), } } } else { - diags::unexpected_cfg_name::CodeSuggestion::SimilarName { + lints::unexpected_cfg_name::CodeSuggestion::SimilarName { span: name_span, code: best_match.to_string(), expected: get_possibilities_sub(), } } } else { - diags::unexpected_cfg_name::CodeSuggestion::SimilarName { + lints::unexpected_cfg_name::CodeSuggestion::SimilarName { span: name_span, code: best_match.to_string(), expected: None, @@ -218,7 +214,7 @@ pub(crate) fn unexpected_cfg_name( names_possibilities.sort(); names_possibilities .iter() - .map(|cfg_name| diags::unexpected_cfg_name::FoundWithSimilarValue { + .map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue { span: name_span, code: format!("{cfg_name} = \"{name}\""), }) @@ -232,14 +228,14 @@ pub(crate) fn unexpected_cfg_name( let expected_names = if !possibilities.is_empty() { let possibilities: Vec<_> = possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect(); - Some(diags::unexpected_cfg_name::ExpectedNames { + Some(lints::unexpected_cfg_name::ExpectedNames { possibilities: possibilities.into(), and_more, }) } else { None }; - diags::unexpected_cfg_name::CodeSuggestion::SimilarValues { + lints::unexpected_cfg_name::CodeSuggestion::SimilarValues { with_similar_values: similar_values, expected_names, } @@ -255,29 +251,29 @@ pub(crate) fn unexpected_cfg_name( } else { None }; - diags::unexpected_cfg_name::InvocationHelp::Cargo { + lints::unexpected_cfg_name::InvocationHelp::Cargo { help, macro_help: cargo_macro_help(tcx, name_span), } } else { - let help = diags::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)); - diags::unexpected_cfg_name::InvocationHelp::Rustc { + let help = lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)); + lints::unexpected_cfg_name::InvocationHelp::Rustc { help, macro_help: rustc_macro_help(name_span), } }; - diags::UnexpectedCfgName { code_sugg, invocation_help, name } + lints::UnexpectedCfgName { code_sugg, invocation_help, name } } -pub(crate) fn unexpected_cfg_value( +pub(super) fn unexpected_cfg_value( sess: &Session, tcx: Option>, (name, name_span): (Symbol, Span), value: Option<(Symbol, Span)>, -) -> diags::UnexpectedCfgValue { +) -> lints::UnexpectedCfgValue { let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else { - panic!( + bug!( "it shouldn't be possible to have a diagnostic on a value whose name is not in values" ); }; @@ -304,7 +300,7 @@ pub(crate) fn unexpected_cfg_value( possibilities.clone(), FilterWellKnownNames::No, ); - diags::unexpected_cfg_value::ExpectedValues { + lints::unexpected_cfg_value::ExpectedValues { name, have_none_possibility, possibilities: possibilities.into(), @@ -315,7 +311,7 @@ pub(crate) fn unexpected_cfg_value( let suggestion = if let Some((value, value_span)) = value { // Suggest the most probable if we found one if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) { - Some(diags::unexpected_cfg_value::ChangeValueSuggestion::SimilarName { + Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName { span: value_span, best_match, }) @@ -323,7 +319,7 @@ pub(crate) fn unexpected_cfg_value( None } } else if let &[first_possibility] = &possibilities[..] { - Some(diags::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue { + Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue { span: name_span.shrink_to_hi(), first_possibility, }) @@ -331,21 +327,21 @@ pub(crate) fn unexpected_cfg_value( None }; - diags::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion } + lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion } } else if have_none_possibility { let suggestion = - value.map(|(_value, value_span)| diags::unexpected_cfg_value::RemoveValueSuggestion { + value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion { span: name_span.shrink_to_hi().to(value_span), }); - diags::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name } + lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name } } else { let span = if let Some((_value, value_span)) = value { name_span.to(value_span) } else { name_span }; - let suggestion = diags::unexpected_cfg_value::RemoveConditionSuggestion { span }; - diags::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name } + let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span }; + lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name } }; // We don't want to encourage people to add values to a well-known names, as these are @@ -366,32 +362,32 @@ pub(crate) fn unexpected_cfg_value( let invocation_help = if is_from_cargo { let help = if name == sym::feature && !is_from_external_macro { if let Some((value, _value_span)) = value { - Some(diags::unexpected_cfg_value::CargoHelp::AddFeature { value }) + Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value }) } else { - Some(diags::unexpected_cfg_value::CargoHelp::DefineFeatures) + Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures) } } else if can_suggest_adding_value && !is_from_external_macro { - Some(diags::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst))) + Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst))) } else { None }; - diags::unexpected_cfg_value::InvocationHelp::Cargo { + lints::unexpected_cfg_value::InvocationHelp::Cargo { help, macro_help: cargo_macro_help(tcx, name_span), } } else { let help = if can_suggest_adding_value { - Some(diags::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No))) + Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No))) } else { None }; - diags::unexpected_cfg_value::InvocationHelp::Rustc { + lints::unexpected_cfg_value::InvocationHelp::Rustc { help, macro_help: rustc_macro_help(name_span), } }; - diags::UnexpectedCfgValue { + lints::UnexpectedCfgValue { code_sugg, invocation_help, has_value: value.is_some(), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c92ef25ac435f..f99d3fc5e98e3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2219,6 +2219,321 @@ pub(crate) enum InvalidAsmLabel { }, } +#[derive(Subdiagnostic)] +pub(crate) enum UnexpectedCfgCargoHelp { + #[help(lint_unexpected_cfg_add_cargo_feature)] + #[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)] + LintCfg { cargo_toml_lint_cfg: String }, + #[help(lint_unexpected_cfg_add_cargo_feature)] + #[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)] + #[help(lint_unexpected_cfg_add_build_rs_println)] + LintCfgAndBuildRs { cargo_toml_lint_cfg: String, build_rs_println: String }, +} + +impl UnexpectedCfgCargoHelp { + fn cargo_toml_lint_cfg(unescaped: &str) -> String { + format!( + "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}" + ) + } + + pub(crate) fn lint_cfg(unescaped: &str) -> Self { + UnexpectedCfgCargoHelp::LintCfg { + cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), + } + } + + pub(crate) fn lint_cfg_and_build_rs(unescaped: &str, escaped: &str) -> Self { + UnexpectedCfgCargoHelp::LintCfgAndBuildRs { + cargo_toml_lint_cfg: Self::cargo_toml_lint_cfg(unescaped), + build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");"), + } + } +} + +#[derive(Subdiagnostic)] +#[help(lint_unexpected_cfg_add_cmdline_arg)] +pub(crate) struct UnexpectedCfgRustcHelp { + pub cmdline_arg: String, +} + +impl UnexpectedCfgRustcHelp { + pub(crate) fn new(unescaped: &str) -> Self { + Self { cmdline_arg: format!("--check-cfg={unescaped}") } + } +} + +#[derive(Subdiagnostic)] +#[note(lint_unexpected_cfg_from_external_macro_origin)] +#[help(lint_unexpected_cfg_from_external_macro_refer)] +pub(crate) struct UnexpectedCfgRustcMacroHelp { + pub macro_kind: &'static str, + pub macro_name: Symbol, +} + +#[derive(Subdiagnostic)] +#[note(lint_unexpected_cfg_from_external_macro_origin)] +#[help(lint_unexpected_cfg_from_external_macro_refer)] +#[help(lint_unexpected_cfg_cargo_update)] +pub(crate) struct UnexpectedCfgCargoMacroHelp { + pub macro_kind: &'static str, + pub macro_name: Symbol, + pub crate_name: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(lint_unexpected_cfg_name)] +pub(crate) struct UnexpectedCfgName { + #[subdiagnostic] + pub code_sugg: unexpected_cfg_name::CodeSuggestion, + #[subdiagnostic] + pub invocation_help: unexpected_cfg_name::InvocationHelp, + + pub name: Symbol, +} + +pub(crate) mod unexpected_cfg_name { + use rustc_errors::DiagSymbolList; + use rustc_macros::Subdiagnostic; + use rustc_span::{Ident, Span, Symbol}; + + #[derive(Subdiagnostic)] + pub(crate) enum CodeSuggestion { + #[help(lint_unexpected_cfg_define_features)] + DefineFeatures, + #[multipart_suggestion( + lint_unexpected_cfg_name_version_syntax, + applicability = "machine-applicable" + )] + VersionSyntax { + #[suggestion_part(code = "(")] + between_name_and_value: Span, + #[suggestion_part(code = ")")] + after_value: Span, + }, + #[suggestion( + lint_unexpected_cfg_name_similar_name_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameAndValue { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + lint_unexpected_cfg_name_similar_name_no_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameNoValue { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + lint_unexpected_cfg_name_similar_name_different_values, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarNameDifferentValues { + #[primary_span] + span: Span, + code: String, + #[subdiagnostic] + expected: Option, + }, + #[suggestion( + lint_unexpected_cfg_name_similar_name, + applicability = "maybe-incorrect", + code = "{code}" + )] + SimilarName { + #[primary_span] + span: Span, + code: String, + #[subdiagnostic] + expected: Option, + }, + SimilarValues { + #[subdiagnostic] + with_similar_values: Vec, + #[subdiagnostic] + expected_names: Option, + }, + } + + #[derive(Subdiagnostic)] + #[help(lint_unexpected_cfg_name_expected_values)] + pub(crate) struct ExpectedValues { + pub best_match: Symbol, + pub possibilities: DiagSymbolList, + } + + #[derive(Subdiagnostic)] + #[suggestion( + lint_unexpected_cfg_name_with_similar_value, + applicability = "maybe-incorrect", + code = "{code}" + )] + pub(crate) struct FoundWithSimilarValue { + #[primary_span] + pub span: Span, + pub code: String, + } + + #[derive(Subdiagnostic)] + #[help_once(lint_unexpected_cfg_name_expected_names)] + pub(crate) struct ExpectedNames { + pub possibilities: DiagSymbolList, + pub and_more: usize, + } + + #[derive(Subdiagnostic)] + pub(crate) enum InvocationHelp { + #[note(lint_unexpected_cfg_doc_cargo)] + Cargo { + #[subdiagnostic] + macro_help: Option, + #[subdiagnostic] + help: Option, + }, + #[note(lint_unexpected_cfg_doc_rustc)] + Rustc { + #[subdiagnostic] + macro_help: Option, + #[subdiagnostic] + help: super::UnexpectedCfgRustcHelp, + }, + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_unexpected_cfg_value)] +pub(crate) struct UnexpectedCfgValue { + #[subdiagnostic] + pub code_sugg: unexpected_cfg_value::CodeSuggestion, + #[subdiagnostic] + pub invocation_help: unexpected_cfg_value::InvocationHelp, + + pub has_value: bool, + pub value: String, +} + +pub(crate) mod unexpected_cfg_value { + use rustc_errors::DiagSymbolList; + use rustc_macros::Subdiagnostic; + use rustc_span::{Span, Symbol}; + + #[derive(Subdiagnostic)] + pub(crate) enum CodeSuggestion { + ChangeValue { + #[subdiagnostic] + expected_values: ExpectedValues, + #[subdiagnostic] + suggestion: Option, + }, + #[note(lint_unexpected_cfg_value_no_expected_value)] + RemoveValue { + #[subdiagnostic] + suggestion: Option, + + name: Symbol, + }, + #[note(lint_unexpected_cfg_value_no_expected_values)] + RemoveCondition { + #[subdiagnostic] + suggestion: RemoveConditionSuggestion, + + name: Symbol, + }, + } + + #[derive(Subdiagnostic)] + pub(crate) enum ChangeValueSuggestion { + #[suggestion( + lint_unexpected_cfg_value_similar_name, + code = r#""{best_match}""#, + applicability = "maybe-incorrect" + )] + SimilarName { + #[primary_span] + span: Span, + best_match: Symbol, + }, + #[suggestion( + lint_unexpected_cfg_value_specify_value, + code = r#" = "{first_possibility}""#, + applicability = "maybe-incorrect" + )] + SpecifyValue { + #[primary_span] + span: Span, + first_possibility: Symbol, + }, + } + + #[derive(Subdiagnostic)] + #[suggestion( + lint_unexpected_cfg_value_remove_value, + code = "", + applicability = "maybe-incorrect" + )] + pub(crate) struct RemoveValueSuggestion { + #[primary_span] + pub span: Span, + } + + #[derive(Subdiagnostic)] + #[suggestion( + lint_unexpected_cfg_value_remove_condition, + code = "", + applicability = "maybe-incorrect" + )] + pub(crate) struct RemoveConditionSuggestion { + #[primary_span] + pub span: Span, + } + + #[derive(Subdiagnostic)] + #[note(lint_unexpected_cfg_value_expected_values)] + pub(crate) struct ExpectedValues { + pub name: Symbol, + pub have_none_possibility: bool, + pub possibilities: DiagSymbolList, + pub and_more: usize, + } + + #[derive(Subdiagnostic)] + pub(crate) enum InvocationHelp { + #[note(lint_unexpected_cfg_doc_cargo)] + Cargo { + #[subdiagnostic] + help: Option, + #[subdiagnostic] + macro_help: Option, + }, + #[note(lint_unexpected_cfg_doc_rustc)] + Rustc { + #[subdiagnostic] + help: Option, + #[subdiagnostic] + macro_help: Option, + }, + } + + #[derive(Subdiagnostic)] + pub(crate) enum CargoHelp { + #[help(lint_unexpected_cfg_value_add_feature)] + AddFeature { + value: Symbol, + }, + #[help(lint_unexpected_cfg_define_features)] + DefineFeatures, + Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp), + } +} + #[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] #[help] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 87834de19cb81..0ddc2e3076e92 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -636,6 +636,8 @@ pub enum BuiltinLintDiag { }, BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), + UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), + UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), SingleUseLifetime { /// Span of the parameter which declares this lifetime. diff --git a/triagebot.toml b/triagebot.toml index 4cb107eb08bd2..79b5c2d1b7238 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -956,7 +956,7 @@ cc = ["@Nadrieril"] message = "Some changes occurred in cfg and check-cfg configuration" cc = ["@Urgau"] -[mentions."compiler/rustc_attr_parsing/src/attributes/cfg/check_cfg.rs"] +[mentions."compiler/rustc_lint/src/early/diagnostics/check_cfg.rs"] message = "Some changes occurred in check-cfg diagnostics" cc = ["@Urgau"]