Skip to content

Commit abc7681

Browse files
committed
Auto merge of #97456 - Bryysen:issue-97319-fix, r=compiler-errors
Improve error message for E0081 Closes #97319
2 parents 0f06824 + f671bc9 commit abc7681

File tree

9 files changed

+174
-76
lines changed

9 files changed

+174
-76
lines changed

compiler/rustc_typeck/src/check/check.rs

+35-16
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,8 @@ fn check_enum<'tcx>(
13761376
}
13771377

13781378
let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
1379+
// This tracks the previous variant span (in the loop) incase we need it for diagnostics
1380+
let mut prev_variant_span: Span = DUMMY_SP;
13791381
for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
13801382
// Check for duplicate discriminant values
13811383
if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
@@ -1390,42 +1392,59 @@ fn check_enum<'tcx>(
13901392
Some(ref expr) => tcx.hir().span(expr.hir_id),
13911393
None => v.span,
13921394
};
1393-
let display_discr = display_discriminant_value(tcx, v, discr.val);
1394-
let display_discr_i = display_discriminant_value(tcx, variant_i, disr_vals[i].val);
1395-
struct_span_err!(
1395+
let display_discr = format_discriminant_overflow(tcx, v, discr);
1396+
let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]);
1397+
let no_disr = v.disr_expr.is_none();
1398+
let mut err = struct_span_err!(
13961399
tcx.sess,
1397-
span,
1400+
sp,
13981401
E0081,
1399-
"discriminant value `{}` already exists",
1400-
discr.val,
1401-
)
1402-
.span_label(i_span, format!("first use of {display_discr_i}"))
1403-
.span_label(span, format!("enum already has {display_discr}"))
1404-
.emit();
1402+
"discriminant value `{}` assigned more than once",
1403+
discr,
1404+
);
1405+
1406+
err.span_label(i_span, format!("first assignment of {display_discr_i}"));
1407+
err.span_label(span, format!("second assignment of {display_discr}"));
1408+
1409+
if no_disr {
1410+
err.span_label(
1411+
prev_variant_span,
1412+
format!(
1413+
"assigned discriminant for `{}` was incremented from this discriminant",
1414+
v.ident
1415+
),
1416+
);
1417+
}
1418+
err.emit();
14051419
}
1420+
14061421
disr_vals.push(discr);
1422+
prev_variant_span = v.span;
14071423
}
14081424

14091425
check_representable(tcx, sp, def_id);
14101426
check_transparent(tcx, sp, def);
14111427
}
14121428

1413-
/// Format an enum discriminant value for use in a diagnostic message.
1414-
fn display_discriminant_value<'tcx>(
1429+
/// In the case that a discriminant is both a duplicate and an overflowing literal,
1430+
/// we insert both the assigned discriminant and the literal it overflowed from into the formatted
1431+
/// output. Otherwise we format the discriminant normally.
1432+
fn format_discriminant_overflow<'tcx>(
14151433
tcx: TyCtxt<'tcx>,
14161434
variant: &hir::Variant<'_>,
1417-
evaluated: u128,
1435+
dis: Discr<'tcx>,
14181436
) -> String {
14191437
if let Some(expr) = &variant.disr_expr {
14201438
let body = &tcx.hir().body(expr.body).value;
14211439
if let hir::ExprKind::Lit(lit) = &body.kind
14221440
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
1423-
&& evaluated != *lit_value
1441+
&& dis.val != *lit_value
14241442
{
1425-
return format!("`{evaluated}` (overflowed from `{lit_value}`)");
1443+
return format!("`{dis}` (overflowed from `{lit_value}`)");
14261444
}
14271445
}
1428-
format!("`{}`", evaluated)
1446+
1447+
format!("`{dis}`")
14291448
}
14301449

14311450
pub(super) fn check_type_params_are_used<'tcx>(

src/test/ui/enum/enum-discrim-autosizing.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
// so force the repr.
55
#[cfg_attr(not(target_pointer_width = "32"), repr(i32))]
66
enum Eu64 {
7-
Au64 = 0, //~NOTE first use of `0`
7+
//~^ ERROR discriminant value `0` assigned more than once
8+
Au64 = 0,
9+
//~^NOTE first assignment of `0`
810
Bu64 = 0x8000_0000_0000_0000
9-
//~^ ERROR discriminant value `0` already exists
10-
//~| NOTE enum already has `0` (overflowed from `9223372036854775808`)
11+
//~^NOTE second assignment of `0` (overflowed from `9223372036854775808`)
1112
}
1213

1314
fn main() {}

src/test/ui/enum/enum-discrim-autosizing.stderr

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
error[E0081]: discriminant value `0` already exists
2-
--> $DIR/enum-discrim-autosizing.rs:8:12
1+
error[E0081]: discriminant value `0` assigned more than once
2+
--> $DIR/enum-discrim-autosizing.rs:6:1
33
|
4-
LL | Au64 = 0,
5-
| - first use of `0`
6-
LL | Bu64 = 0x8000_0000_0000_0000
7-
| ^^^^^^^^^^^^^^^^^^^^^ enum already has `0` (overflowed from `9223372036854775808`)
4+
LL | / enum Eu64 {
5+
LL | |
6+
LL | | Au64 = 0,
7+
| | - first assignment of `0`
8+
LL | |
9+
LL | | Bu64 = 0x8000_0000_0000_0000
10+
| | --------------------- second assignment of `0` (overflowed from `9223372036854775808`)
11+
LL | |
12+
LL | | }
13+
| |_^
814

915
error: aborting due to previous error
1016

src/test/ui/error-codes/E0081.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
enum Enum {
2+
//~^ ERROR discriminant value `3` assigned more than once
23
P = 3,
3-
//~^ NOTE first use of `3`
4+
//~^ NOTE first assignment of `3`
45
X = 3,
5-
//~^ ERROR discriminant value `3` already exists
6-
//~| NOTE enum already has `3`
6+
//~^ NOTE second assignment of `3`
77
Y = 5
88
}
99

1010
#[repr(u8)]
1111
enum EnumOverflowRepr {
12+
//~^ ERROR discriminant value `1` assigned more than once
1213
P = 257,
13-
//~^ NOTE first use of `1` (overflowed from `257`)
14+
//~^ NOTE first assignment of `1` (overflowed from `257`)
1415
X = 513,
15-
//~^ ERROR discriminant value `1` already exists
16-
//~| NOTE enum already has `1` (overflowed from `513`)
16+
//~^ NOTE second assignment of `1` (overflowed from `513`)
17+
}
18+
19+
#[repr(i8)]
20+
enum NegDisEnum {
21+
//~^ ERROR discriminant value `-1` assigned more than once
22+
First = -1,
23+
//~^ NOTE first assignment of `-1`
24+
Second = -2,
25+
//~^ NOTE assigned discriminant for `Last` was incremented from this discriminant
26+
Last,
27+
//~^ NOTE second assignment of `-1`
1728
}
1829

1930
fn main() {

src/test/ui/error-codes/E0081.stderr

+43-15
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
1-
error[E0081]: discriminant value `3` already exists
2-
--> $DIR/E0081.rs:4:9
1+
error[E0081]: discriminant value `3` assigned more than once
2+
--> $DIR/E0081.rs:1:1
33
|
4-
LL | P = 3,
5-
| - first use of `3`
6-
LL |
7-
LL | X = 3,
8-
| ^ enum already has `3`
4+
LL | / enum Enum {
5+
LL | |
6+
LL | | P = 3,
7+
| | - first assignment of `3`
8+
LL | |
9+
LL | | X = 3,
10+
| | - second assignment of `3`
11+
LL | |
12+
LL | | Y = 5
13+
LL | | }
14+
| |_^
915

10-
error[E0081]: discriminant value `1` already exists
11-
--> $DIR/E0081.rs:14:9
16+
error[E0081]: discriminant value `1` assigned more than once
17+
--> $DIR/E0081.rs:11:1
1218
|
13-
LL | P = 257,
14-
| --- first use of `1` (overflowed from `257`)
15-
LL |
16-
LL | X = 513,
17-
| ^^^ enum already has `1` (overflowed from `513`)
19+
LL | / enum EnumOverflowRepr {
20+
LL | |
21+
LL | | P = 257,
22+
| | --- first assignment of `1` (overflowed from `257`)
23+
LL | |
24+
LL | | X = 513,
25+
| | --- second assignment of `1` (overflowed from `513`)
26+
LL | |
27+
LL | | }
28+
| |_^
1829

19-
error: aborting due to 2 previous errors
30+
error[E0081]: discriminant value `-1` assigned more than once
31+
--> $DIR/E0081.rs:20:1
32+
|
33+
LL | / enum NegDisEnum {
34+
LL | |
35+
LL | | First = -1,
36+
| | -- first assignment of `-1`
37+
LL | |
38+
LL | | Second = -2,
39+
| | ----------- assigned discriminant for `Last` was incremented from this discriminant
40+
LL | |
41+
LL | | Last,
42+
| | ---- second assignment of `-1`
43+
LL | |
44+
LL | | }
45+
| |_^
46+
47+
error: aborting due to 3 previous errors
2048

2149
For more information about this error, try `rustc --explain E0081`.

src/test/ui/issues/issue-15524.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
const N: isize = 1;
22

33
enum Foo {
4+
//~^ ERROR discriminant value `1` assigned more than once
5+
//~| ERROR discriminant value `1` assigned more than once
6+
//~| ERROR discriminant value `1` assigned more than once
47
A = 1,
58
B = 1,
6-
//~^ ERROR discriminant value `1` already exists
79
C = 0,
810
D,
9-
//~^ ERROR discriminant value `1` already exists
1011

1112
E = N,
12-
//~^ ERROR discriminant value `1` already exists
1313

1414
}
1515

src/test/ui/issues/issue-15524.stderr

+45-20
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,53 @@
1-
error[E0081]: discriminant value `1` already exists
2-
--> $DIR/issue-15524.rs:5:9
1+
error[E0081]: discriminant value `1` assigned more than once
2+
--> $DIR/issue-15524.rs:3:1
33
|
4-
LL | A = 1,
5-
| - first use of `1`
6-
LL | B = 1,
7-
| ^ enum already has `1`
4+
LL | / enum Foo {
5+
LL | |
6+
LL | |
7+
LL | |
8+
LL | | A = 1,
9+
| | - first assignment of `1`
10+
LL | | B = 1,
11+
| | - second assignment of `1`
12+
... |
13+
LL | |
14+
LL | | }
15+
| |_^
816

9-
error[E0081]: discriminant value `1` already exists
10-
--> $DIR/issue-15524.rs:8:5
17+
error[E0081]: discriminant value `1` assigned more than once
18+
--> $DIR/issue-15524.rs:3:1
1119
|
12-
LL | A = 1,
13-
| - first use of `1`
14-
...
15-
LL | D,
16-
| ^ enum already has `1`
20+
LL | / enum Foo {
21+
LL | |
22+
LL | |
23+
LL | |
24+
LL | | A = 1,
25+
| | - first assignment of `1`
26+
LL | | B = 1,
27+
LL | | C = 0,
28+
| | ----- assigned discriminant for `D` was incremented from this discriminant
29+
LL | | D,
30+
| | - second assignment of `1`
31+
... |
32+
LL | |
33+
LL | | }
34+
| |_^
1735

18-
error[E0081]: discriminant value `1` already exists
19-
--> $DIR/issue-15524.rs:11:9
36+
error[E0081]: discriminant value `1` assigned more than once
37+
--> $DIR/issue-15524.rs:3:1
2038
|
21-
LL | A = 1,
22-
| - first use of `1`
23-
...
24-
LL | E = N,
25-
| ^ enum already has `1`
39+
LL | / enum Foo {
40+
LL | |
41+
LL | |
42+
LL | |
43+
LL | | A = 1,
44+
| | - first assignment of `1`
45+
... |
46+
LL | | E = N,
47+
| | - second assignment of `1`
48+
LL | |
49+
LL | | }
50+
| |_^
2651

2752
error: aborting due to 3 previous errors
2853

src/test/ui/tag-variant-disr-dup.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Black and White have the same discriminator value ...
22

33
enum Color {
4+
//~^ ERROR discriminant value `0` assigned more than once
45
Red = 0xff0000,
56
Green = 0x00ff00,
67
Blue = 0x0000ff,
78
Black = 0x000000,
8-
White = 0x000000, //~ ERROR discriminant value `0` already exists
9+
White = 0x000000,
910
}
1011

1112
fn main() { }

src/test/ui/tag-variant-disr-dup.stderr

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
error[E0081]: discriminant value `0` already exists
2-
--> $DIR/tag-variant-disr-dup.rs:8:13
1+
error[E0081]: discriminant value `0` assigned more than once
2+
--> $DIR/tag-variant-disr-dup.rs:3:1
33
|
4-
LL | Black = 0x000000,
5-
| -------- first use of `0`
6-
LL | White = 0x000000,
7-
| ^^^^^^^^ enum already has `0`
4+
LL | / enum Color {
5+
LL | |
6+
LL | | Red = 0xff0000,
7+
LL | | Green = 0x00ff00,
8+
LL | | Blue = 0x0000ff,
9+
LL | | Black = 0x000000,
10+
| | -------- first assignment of `0`
11+
LL | | White = 0x000000,
12+
| | -------- second assignment of `0`
13+
LL | | }
14+
| |_^
815

916
error: aborting due to previous error
1017

0 commit comments

Comments
 (0)