Skip to content

Commit cac4317

Browse files
mdietz94mj10021
authored andcommitted
addind new lint
1 parent 60d1465 commit cac4317

File tree

6 files changed

+108
-5
lines changed

6 files changed

+108
-5
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+33
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,39 @@ declare_lint! {
17031703
"functions that cannot return without calling themselves"
17041704
}
17051705

1706+
declare_lint! {
1707+
/// The `recursive_dafault_impl` lint detects functions that cannot
1708+
/// return without calling themselves.
1709+
///
1710+
/// ### Example
1711+
///
1712+
/// ```rust
1713+
/// struct Foo {
1714+
/// bar: u32
1715+
/// }
1716+
/// impl Default for Foo {
1717+
/// fn default() -> Self {
1718+
/// Self {
1719+
/// ..Default::default()
1720+
/// }
1721+
/// }
1722+
///
1723+
/// let _ = Foo::default();
1724+
/// ```
1725+
///
1726+
/// {{produces}}
1727+
///
1728+
/// ### Explanation
1729+
///
1730+
/// This is a specific case of unconditional recursion where the default
1731+
/// trait is implemented recursively, errantly trying to apply the
1732+
/// default struct for this field. This will always lead to an infinite loop
1733+
/// so it is denied.
1734+
pub RECURSIVE_DEFAULT_IMPL,
1735+
Deny,
1736+
"functions that cannot return without calling themselves"
1737+
}
1738+
17061739
declare_lint! {
17071740
/// The `single_use_lifetimes` lint detects lifetimes that are only used
17081741
/// once.

compiler/rustc_mir_build/messages.ftl

+7
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,12 @@ 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 = recursive default impl
269+
.label = will result in infinite recursion
270+
.help = ..default() in the Default impl does not apply a default for each struct field
271+
272+
mir_build_recursive_default_impl_call_site_label = recursive call site
273+
268274
mir_build_rust_2024_incompatible_pat = the semantics of this pattern will change in edition 2024
269275
270276
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
@@ -313,6 +319,7 @@ mir_build_unconditional_recursion = function cannot return without recursing
313319
314320
mir_build_unconditional_recursion_call_site_label = recursive call site
315321
322+
316323
mir_build_union_field_requires_unsafe =
317324
access to union field is unsafe and requires unsafe block
318325
.note = the field may not be properly initialized: using uninitialized data will cause undefined behavior

compiler/rustc_mir_build/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ use rustc_span::Span;
1212

1313
use crate::fluent_generated as fluent;
1414

15+
#[derive(LintDiagnostic)]
16+
#[diag(mir_build_recursive_default_impl)]
17+
#[help]
18+
pub(crate) struct RecursiveDefaultImpl {
19+
#[label]
20+
pub(crate) span: Span,
21+
#[label(mir_build_recursive_default_impl_call_site_label)]
22+
pub(crate) call_sites: Vec<Span>,
23+
}
24+
1525
#[derive(LintDiagnostic)]
1626
#[diag(mir_build_unconditional_recursion)]
1727
#[help]

compiler/rustc_mir_build/src/lints.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ use rustc_data_structures::graph::iterate::{
66
use rustc_hir::def::DefKind;
77
use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind};
88
use rustc_middle::ty::{self, GenericArg, GenericArgs, Instance, Ty, TyCtxt};
9-
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
10-
use rustc_span::Span;
9+
use rustc_session::lint::builtin::{RECURSIVE_DEFAULT_IMPL, UNCONDITIONAL_RECURSION};
10+
use rustc_span::{sym, 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);
@@ -49,11 +49,29 @@ fn check_recursion<'tcx>(
4949
if vis.reachable_recursive_calls.is_empty() {
5050
return;
5151
}
52-
5352
vis.reachable_recursive_calls.sort();
54-
5553
let sp = tcx.def_span(def_id);
5654
let hir_id = tcx.local_def_id_to_hir_id(def_id);
55+
// emit a different error for recursive default impls
56+
if tcx.def_kind(def_id) == DefKind::AssocFn {
57+
// Check if this is a trait impl and get the defid of the trait if it is
58+
if let Some(trait_def_id) = tcx.trait_id_of_impl(tcx.parent(def_id.into())) {
59+
// check if it is a default impl
60+
if tcx.get_diagnostic_name(trait_def_id) == Some(sym::Default) {
61+
tcx.emit_node_span_lint(
62+
RECURSIVE_DEFAULT_IMPL,
63+
hir_id,
64+
sp,
65+
RecursiveDefaultImpl {
66+
span: sp,
67+
call_sites: vis.reachable_recursive_calls,
68+
},
69+
);
70+
return;
71+
}
72+
}
73+
}
74+
5775
tcx.emit_node_span_lint(
5876
UNCONDITIONAL_RECURSION,
5977
hir_id,
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@check-fail
2+
3+
struct Foo{
4+
bar: u32,
5+
}
6+
7+
impl Default for Foo {
8+
fn default() -> Self {
9+
Self {
10+
..Default::default()
11+
//~^ ERROR: recursive default impl
12+
}
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0601]: `main` function not found in crate `recursive_default_impl`
2+
--> $DIR/recursive_default_impl.rs:12:2
3+
|
4+
LL | }
5+
| ^ consider adding a `main` function to `$DIR/recursive_default_impl.rs`
6+
7+
error: recursive default impl
8+
--> $DIR/recursive_default_impl.rs:6:5
9+
|
10+
LL | fn default() -> Self {
11+
| ^^^^^^^^^^^^^^^^^^^^ will result in infinite recursion
12+
LL | Self {
13+
LL | ..Default::default()
14+
| ------------------ recursive call site
15+
|
16+
= help: ..default() in the Default impl does not apply a default for each struct field
17+
= note: `#[deny(recursive_default_impl)]` on by default
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0601`.

0 commit comments

Comments
 (0)