diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 55149570dbc4d..d807704a8ef6b 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -265,6 +265,8 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future +mir_build_recursive_default_impl = calling `..Default::default()` in a `Default` implementation leads to infinite recursion, and does not initialize the fields of a struct or enum + mir_build_rust_2024_incompatible_pat = patterns are not allowed to reset the default binding mode in edition 2024 mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 676f7c98b8f88..c831564363f7f 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -18,6 +18,8 @@ use crate::fluent_generated as fluent; pub(crate) struct UnconditionalRecursion { #[label] pub(crate) span: Span, + #[help(mir_build_recursive_default_impl)] + pub(crate) default_impl_note: Option<()>, #[label(mir_build_unconditional_recursion_call_site_label)] pub(crate) call_sites: Vec, } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 5cf33868adeee..e4e09782f26bf 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -7,7 +7,8 @@ use rustc_hir::def::DefKind; use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind}; use rustc_middle::ty::{self, GenericArg, GenericArgs, Instance, Ty, TyCtxt}; use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; -use rustc_span::Span; +use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; use crate::errors::UnconditionalRecursion; @@ -32,6 +33,19 @@ fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { } } +fn is_default_impl<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + // Check if this is a trait impl and get the defid of the trait if it is + if tcx.def_kind(def_id) == DefKind::AssocFn + && let Some(parent_def_id) = tcx.opt_parent(def_id.into()) + && tcx.def_kind(parent_def_id) == (DefKind::Impl { of_trait: true }) + && let Some(trait_def_id) = tcx.trait_id_of_impl(parent_def_id) + { + // check if it is a default impl + return tcx.get_diagnostic_name(trait_def_id) == Some(sym::Default); + } + false +} + fn check_recursion<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, @@ -57,6 +71,7 @@ fn check_recursion<'tcx>( tcx.emit_node_span_lint(UNCONDITIONAL_RECURSION, hir_id, sp, UnconditionalRecursion { span: sp, call_sites: vis.reachable_recursive_calls, + default_impl_note: is_default_impl(tcx, def_id).then(|| ()), }); } } diff --git a/tests/ui/lint/lint-unconditional-recursion.stderr b/tests/ui/lint/lint-unconditional-recursion.stderr index d75754bf9f900..e913e229e2ec8 100644 --- a/tests/ui/lint/lint-unconditional-recursion.stderr +++ b/tests/ui/lint/lint-unconditional-recursion.stderr @@ -122,6 +122,7 @@ LL | let x = Default::default(); | ------------------ recursive call site | = help: a `loop` may express intention better if this is on purpose + = help: calling `..Default::default()` in a `Default` implementation leads to infinite recursion, and does not initialize the fields of a struct or enum error: function cannot return without recursing --> $DIR/lint-unconditional-recursion.rs:102:5 @@ -196,6 +197,7 @@ LL | ..Default::default() | ------------------ recursive call site | = help: a `loop` may express intention better if this is on purpose + = help: calling `..Default::default()` in a `Default` implementation leads to infinite recursion, and does not initialize the fields of a struct or enum error: aborting due to 18 previous errors