Skip to content

Commit 69d3ea3

Browse files
committed
Split lints
1 parent 2e98ce6 commit 69d3ea3

4 files changed

+84
-20
lines changed

compiler/rustc_lint/src/default_could_be_derived.rs

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ declare_lint! {
1515
/// ### Example
1616
///
1717
/// ```rust,compile_fail
18+
/// struct A {
19+
/// b: Option<i32>,
20+
/// }
21+
///
22+
/// #[deny(default_could_be_derived)]
23+
/// impl Default for Foo {
24+
/// fn default() -> Foo {
25+
/// A {
26+
/// b: None,
27+
/// }
28+
/// }
29+
/// }
30+
///
1831
/// enum Foo {
1932
/// Bar,
2033
/// }
@@ -29,12 +42,56 @@ declare_lint! {
2942
///
3043
/// {{produces}}
3144
///
45+
/// ### Explanation
46+
///
47+
/// `#[derive(Default)]` uses the `Default` impl for every field of your
48+
/// type. If your manual `Default` impl either invokes `Default::default()`
49+
/// or uses the same value that that associated function produces, then it
50+
/// is better to use the derive to avoid the different `Default` impls from
51+
/// diverging over time.
52+
///
53+
/// This lint also triggers on cases where there the type has no fields,
54+
/// so the derive for `Default` for a struct is trivial, and for an enum
55+
/// variant with no fields, which can be annotated with `#[default]`.
3256
pub DEFAULT_COULD_BE_DERIVED,
3357
Warn,
3458
"detect `Default` impl that could be derived"
3559
}
3660

37-
declare_lint_pass!(DefaultCouldBeDerived => [DEFAULT_COULD_BE_DERIVED]);
61+
declare_lint! {
62+
/// The `default_could_be_derived` lint checks for manual `impl` blocks
63+
/// of the `Default` trait that could have been derived.
64+
///
65+
/// ### Example
66+
///
67+
/// ```rust,compile_fail
68+
/// struct Foo {
69+
/// x: i32 = 101,
70+
/// }
71+
///
72+
/// #[deny(manual_default_for_type_with_default_fields)]
73+
/// impl Default for Foo {
74+
/// fn default() -> Foo {
75+
/// Foo { x: 100 }
76+
/// }
77+
/// }
78+
/// ```
79+
///
80+
/// {{produces}}
81+
///
82+
/// ### Explanation
83+
///
84+
/// Manually writing a `Default` implementation for a type that has
85+
/// default field values runs the risk of diverging behavior between
86+
/// `Type { .. }` and `<Type as Default>::default()`, which would be a
87+
/// foot-gun for users of that type that would expect these to be
88+
/// equivalent.
89+
pub MANUAL_DEFAULT_FOR_TYPE_WITH_DEFAULT_FIELDS,
90+
Warn,
91+
"detect `Default` impl on type with default field values that should be derived"
92+
}
93+
94+
declare_lint_pass!(DefaultCouldBeDerived => [DEFAULT_COULD_BE_DERIVED, MANUAL_DEFAULT_FOR_TYPE_WITH_DEFAULT_FIELDS]);
3895

3996
impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
4097
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
@@ -81,11 +138,13 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
81138
== fields_with_default_value.len() + fields_with_default_impl.len()
82139
{
83140
cx.tcx.node_span_lint(
84-
DEFAULT_COULD_BE_DERIVED,
141+
MANUAL_DEFAULT_FOR_TYPE_WITH_DEFAULT_FIELDS,
85142
item.hir_id(),
86143
item.span,
87144
|diag| {
88-
diag.primary_message("`impl Default` that could be derived");
145+
diag.primary_message(
146+
"manual `Default` impl for type with default field values",
147+
);
89148
let msg = match (
90149
!fields_with_default_value.is_empty(),
91150
!fields_with_default_impl.is_empty(),

tests/ui/structs/manual-default-impl-could-be-derived.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Warn when we encounter a manual `Default` impl that could be derived.
22
//@ run-rustfix
33
#![allow(dead_code)]
4-
#![deny(default_could_be_derived)]
4+
#![deny(default_could_be_derived, manual_default_for_type_with_default_fields)]
55
#![feature(default_field_values)]
66

77
#[derive(Debug)]

tests/ui/structs/manual-default-impl-could-be-derived.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
// Warn when we encounter a manual `Default` impl that could be derived.
22
//@ run-rustfix
33
#![allow(dead_code)]
4-
#![deny(default_could_be_derived)]
4+
#![deny(default_could_be_derived, manual_default_for_type_with_default_fields)]
55
#![feature(default_field_values)]
66

77
#[derive(Debug)]
88
struct A;
99

10-
impl Default for A { //~ ERROR
10+
impl Default for A { //~ ERROR default_could_be_derived
1111
fn default() -> Self { A }
1212
}
1313

1414
#[derive(Debug)]
1515
struct B(Option<i32>);
1616

17-
impl Default for B { //~ ERROR
17+
impl Default for B { //~ ERROR default_could_be_derived
1818
fn default() -> Self { B(Default::default()) }
1919
}
2020

2121
#[derive(Debug)]
2222
struct C(Option<i32>);
2323

24-
impl Default for C { //~ ERROR
24+
impl Default for C { //~ ERROR default_could_be_derived
2525
fn default() -> Self { C(None) }
2626
}
2727

@@ -32,7 +32,7 @@ struct D {
3232
y: i32,
3333
}
3434

35-
impl Default for D { //~ ERROR
35+
impl Default for D { //~ ERROR default_could_be_derived
3636
fn default() -> Self {
3737
D {
3838
x: Default::default(),
@@ -47,7 +47,7 @@ struct E {
4747
x: Option<i32>,
4848
}
4949

50-
impl Default for E { //~ ERROR
50+
impl Default for E { //~ ERROR default_could_be_derived
5151
fn default() -> Self {
5252
E {
5353
x: None,
@@ -61,7 +61,7 @@ enum F<T> {
6161
Tuple(T),
6262
}
6363

64-
impl<T> Default for F<T> { //~ ERROR
64+
impl<T> Default for F<T> { //~ ERROR default_could_be_derived
6565
fn default() -> Self {
6666
F::Unit
6767
}
@@ -72,7 +72,7 @@ struct G {
7272
f: F<i32>,
7373
}
7474

75-
impl Default for G { //~ ERROR
75+
impl Default for G { //~ ERROR default_could_be_derived
7676
fn default() -> Self {
7777
G {
7878
f: F::Unit,
@@ -86,7 +86,7 @@ struct H {
8686
x: i32 = 101,
8787
}
8888

89-
impl Default for H { //~ ERROR
89+
impl Default for H { //~ ERROR [manual_default_for_type_with_default_fields]
9090
fn default() -> Self {
9191
H {
9292
x: 1,
@@ -101,7 +101,7 @@ struct I {
101101
y: Option<i32>,
102102
}
103103

104-
impl Default for I { //~ ERROR
104+
impl Default for I { //~ ERROR [manual_default_for_type_with_default_fields]
105105
fn default() -> Self {
106106
I {
107107
x: 1,
@@ -116,7 +116,7 @@ struct J {
116116
x: K,
117117
}
118118

119-
impl Default for J { //~ ERROR
119+
impl Default for J { //~ ERROR default_could_be_derived
120120
fn default() -> Self {
121121
J {
122122
x: foo(), // fn call that isn't an assoc fn
@@ -141,7 +141,7 @@ struct L {
141141
x: Vec<i32>,
142142
}
143143

144-
impl Default for L { //~ ERROR
144+
impl Default for L { //~ ERROR default_could_be_derived
145145
fn default() -> Self {
146146
L {
147147
x: Vec::new(), // `<Vec as Default>::default()` just calls `Vec::new()`
@@ -154,7 +154,7 @@ struct M {
154154
x: N,
155155
}
156156

157-
impl Default for M { //~ ERROR
157+
impl Default for M { //~ ERROR default_could_be_derived
158158
fn default() -> Self {
159159
M {
160160
x: N_CONST,

tests/ui/structs/manual-default-impl-could-be-derived.stderr

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ LL | | }
1010
note: the lint level is defined here
1111
--> $DIR/manual-default-impl-could-be-derived.rs:4:9
1212
|
13-
LL | #![deny(default_could_be_derived)]
13+
LL | #![deny(default_could_be_derived, manual_default_for_type_with_default_fields)]
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^
1515
help: you don't need to manually `impl Default`, you can derive it
1616
|
@@ -121,7 +121,7 @@ help: you don't need to manually `impl Default`, you can derive it
121121
LL ~ #[derive(Default)] struct G {
122122
|
123123

124-
error: `impl Default` that could be derived
124+
error: manual `Default` impl for type with default field values
125125
--> $DIR/manual-default-impl-could-be-derived.rs:89:1
126126
|
127127
LL | struct H {
@@ -138,12 +138,17 @@ LL | | }
138138
LL | | }
139139
| |_^
140140
|
141+
note: the lint level is defined here
142+
--> $DIR/manual-default-impl-could-be-derived.rs:4:35
143+
|
144+
LL | #![deny(default_could_be_derived, manual_default_for_type_with_default_fields)]
145+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
141146
help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default`
142147
|
143148
LL ~ #[derive(Default)] struct H {
144149
|
145150

146-
error: `impl Default` that could be derived
151+
error: manual `Default` impl for type with default field values
147152
--> $DIR/manual-default-impl-could-be-derived.rs:104:1
148153
|
149154
LL | struct I {

0 commit comments

Comments
 (0)