Skip to content

Commit 82538b7

Browse files
authored
Rollup merge of #118131 - lukas-code:multi-default, r=wesleywiser
improve tool-only help for multiple `#[default]` variants When defining an enum with multiple `#[default]` variants, we emit a tool-only suggestion for every `#[default]`ed variant to remove all other `#[default]`s. This PR improves the suggestion to correctly handle the cases where one variant has multiple `#[default]`s and where different `#[default]`s have the same span due to macro expansions. fixes #118119
2 parents 360bafa + f697a00 commit 82538b7

File tree

5 files changed

+111
-47
lines changed

5 files changed

+111
-47
lines changed

compiler/rustc_builtin_macros/src/deriving/default.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,17 @@ fn extract_default_variant<'a>(
127127
[first, rest @ ..] => {
128128
let suggs = default_variants
129129
.iter()
130-
.map(|variant| {
131-
let spans = default_variants
130+
.filter_map(|variant| {
131+
let keep = attr::find_by_name(&variant.attrs, kw::Default)?.span;
132+
let spans: Vec<Span> = default_variants
132133
.iter()
133-
.filter_map(|v| {
134-
if v.span == variant.span {
135-
None
136-
} else {
137-
Some(attr::find_by_name(&v.attrs, kw::Default)?.span)
138-
}
134+
.flat_map(|v| {
135+
attr::filter_by_name(&v.attrs, kw::Default)
136+
.filter_map(|attr| (attr.span != keep).then_some(attr.span))
139137
})
140138
.collect();
141-
errors::MultipleDefaultsSugg { spans, ident: variant.ident }
139+
(!spans.is_empty())
140+
.then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident })
142141
})
143142
.collect();
144143
cx.emit_err(errors::MultipleDefaults {

tests/ui/deriving/issue-105101.rs

-9
This file was deleted.

tests/ui/deriving/issue-105101.stderr

-29
This file was deleted.
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// compile-flags: --crate-type=lib
2+
3+
// When we get multiple `#[default]` variants, we emit several tool-only suggestions
4+
// to remove all except one of the `#[default]`s.
5+
6+
#[derive(Default)] //~ ERROR multiple declared defaults
7+
enum A {
8+
#[default] //~ HELP make `B` default
9+
#[default] //~ HELP make `A` default
10+
A,
11+
#[default] // also "HELP make `A` default", but compiletest can't handle multispans
12+
B,
13+
}
14+
15+
// Originally, we took each defaulted variant and emitted the suggestion for every variant
16+
// with a different identifier, causing an ICE when multiple variants have the same identifier:
17+
// https://github.com/rust-lang/rust/pull/105106
18+
#[derive(Default)] //~ ERROR multiple declared defaults
19+
enum E {
20+
#[default] //~ HELP make `A` default
21+
A,
22+
#[default] //~ HELP make `A` default
23+
A, //~ ERROR defined multiple times
24+
}
25+
26+
// Then, we took each defaulted variant and emitted the suggestion for every variant
27+
// with a different span, causing an ICE when multiple variants have the same span:
28+
// https://github.com/rust-lang/rust/issues/118119
29+
macro_rules! m {
30+
{ $($id:ident)* } => {
31+
#[derive(Default)] //~ ERROR multiple declared defaults
32+
enum F {
33+
$(
34+
#[default]
35+
$id,
36+
)*
37+
}
38+
}
39+
}
40+
41+
m! { A B }
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
error: multiple declared defaults
2+
--> $DIR/multiple-defaults.rs:6:10
3+
|
4+
LL | #[derive(Default)]
5+
| ^^^^^^^
6+
...
7+
LL | A,
8+
| - first default
9+
LL | #[default] // also "HELP make `A` default", but compiletest can't handle multispans
10+
LL | B,
11+
| - additional default
12+
|
13+
= note: only one variant can be default
14+
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
15+
16+
error: multiple declared defaults
17+
--> $DIR/multiple-defaults.rs:18:10
18+
|
19+
LL | #[derive(Default)]
20+
| ^^^^^^^
21+
...
22+
LL | A,
23+
| - first default
24+
LL | #[default]
25+
LL | A,
26+
| - additional default
27+
|
28+
= note: only one variant can be default
29+
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
30+
31+
error[E0428]: the name `A` is defined multiple times
32+
--> $DIR/multiple-defaults.rs:23:5
33+
|
34+
LL | A,
35+
| - previous definition of the type `A` here
36+
LL | #[default]
37+
LL | A,
38+
| ^ `A` redefined here
39+
|
40+
= note: `A` must be defined only once in the type namespace of this enum
41+
42+
error: multiple declared defaults
43+
--> $DIR/multiple-defaults.rs:31:18
44+
|
45+
LL | #[derive(Default)]
46+
| ^^^^^^^
47+
...
48+
LL | $id,
49+
| ---
50+
| |
51+
| first default
52+
| additional default
53+
...
54+
LL | m! { A B }
55+
| ---------- in this macro invocation
56+
|
57+
= note: only one variant can be default
58+
= note: this error originates in the derive macro `Default` which comes from the expansion of the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
59+
60+
error: aborting due to 4 previous errors
61+
62+
For more information about this error, try `rustc --explain E0428`.

0 commit comments

Comments
 (0)