Skip to content

Commit 1251b2b

Browse files
committed
add check and note for recursive default impl
1 parent 717f5df commit 1251b2b

File tree

4 files changed

+32
-1
lines changed

4 files changed

+32
-1
lines changed

compiler/rustc_mir_build/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from
265265
266266
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
267267
268+
mir_build_recursive_default_impl = ..default() in the Default impl does not apply a default for each struct field
269+
268270
mir_build_rust_2024_incompatible_pat = patterns are not allowed to reset the default binding mode in edition 2024
269271
270272
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly

compiler/rustc_mir_build/src/errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,16 @@ use crate::fluent_generated as fluent;
1818
pub(crate) struct UnconditionalRecursion {
1919
#[label]
2020
pub(crate) span: Span,
21+
#[subdiagnostic]
22+
pub(crate) default_impl_note: Option<RecursiveDefaultImpl>,
2123
#[label(mir_build_unconditional_recursion_call_site_label)]
2224
pub(crate) call_sites: Vec<Span>,
2325
}
2426

27+
#[derive(Subdiagnostic)]
28+
#[help(mir_build_recursive_default_impl)]
29+
pub(crate) struct RecursiveDefaultImpl {}
30+
2531
#[derive(LintDiagnostic)]
2632
#[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)]
2733
pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe {

compiler/rustc_mir_build/src/lints.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_middle::ty::{self, GenericArg, GenericArgs, Instance, Ty, TyCtxt};
99
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
1010
use rustc_span::Span;
1111

12-
use crate::errors::UnconditionalRecursion;
12+
use crate::errors::{RecursiveDefaultImpl, UnconditionalRecursion};
1313

1414
pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
1515
check_call_recursion(tcx, body);
@@ -31,6 +31,24 @@ fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
3131
check_recursion(tcx, body, CallRecursion { trait_args })
3232
}
3333
}
34+
use rustc_span::def_id::LocalDefId;
35+
use rustc_span::sym;
36+
fn is_default_impl<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
37+
if tcx.def_kind(def_id) == DefKind::AssocFn {
38+
// Check if this is a trait impl and get the defid of the trait if it is
39+
if let Some(parent_def_id) = tcx.opt_parent(def_id.into()) {
40+
if tcx.def_kind(parent_def_id) == (DefKind::Impl { of_trait: true }) {
41+
if let Some(trait_def_id) = tcx.trait_id_of_impl(parent_def_id) {
42+
// check if it is a default impl
43+
if tcx.get_diagnostic_name(trait_def_id) == Some(sym::Default) {
44+
return true;
45+
}
46+
}
47+
}
48+
}
49+
}
50+
false
51+
}
3452

3553
fn check_recursion<'tcx>(
3654
tcx: TyCtxt<'tcx>,
@@ -54,9 +72,12 @@ fn check_recursion<'tcx>(
5472

5573
let sp = tcx.def_span(def_id);
5674
let hir_id = tcx.local_def_id_to_hir_id(def_id);
75+
let default_impl_note =
76+
{ if is_default_impl(tcx, def_id) { Some(RecursiveDefaultImpl {}) } else { None } };
5777
tcx.emit_node_span_lint(UNCONDITIONAL_RECURSION, hir_id, sp, UnconditionalRecursion {
5878
span: sp,
5979
call_sites: vis.reachable_recursive_calls,
80+
default_impl_note,
6081
});
6182
}
6283
}

tests/ui/lint/lint-unconditional-recursion.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ LL | let x = Default::default();
122122
| ------------------ recursive call site
123123
|
124124
= help: a `loop` may express intention better if this is on purpose
125+
= help: ..default() in the Default impl does not apply a default for each struct field
125126

126127
error: function cannot return without recursing
127128
--> $DIR/lint-unconditional-recursion.rs:102:5
@@ -196,6 +197,7 @@ LL | ..Default::default()
196197
| ------------------ recursive call site
197198
|
198199
= help: a `loop` may express intention better if this is on purpose
200+
= help: ..default() in the Default impl does not apply a default for each struct field
199201

200202
error: aborting due to 18 previous errors
201203

0 commit comments

Comments
 (0)