Skip to content

Improve error message for E0081 #97456

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 35 additions & 16 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,8 @@ fn check_enum<'tcx>(
}

let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
// This tracks the previous variant span (in the loop) incase we need it for diagnostics
let mut prev_variant_span: Span = DUMMY_SP;
for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
// Check for duplicate discriminant values
if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
Expand All @@ -1390,42 +1392,59 @@ fn check_enum<'tcx>(
Some(ref expr) => tcx.hir().span(expr.hir_id),
None => v.span,
};
let display_discr = display_discriminant_value(tcx, v, discr.val);
let display_discr_i = display_discriminant_value(tcx, variant_i, disr_vals[i].val);
struct_span_err!(
let display_discr = format_discriminant_overflow(tcx, v, discr);
let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]);
let no_disr = v.disr_expr.is_none();
let mut err = struct_span_err!(
tcx.sess,
span,
sp,
E0081,
"discriminant value `{}` already exists",
discr.val,
)
.span_label(i_span, format!("first use of {display_discr_i}"))
.span_label(span, format!("enum already has {display_discr}"))
.emit();
"discriminant value `{}` assigned more than once",
discr,
);

err.span_label(i_span, format!("first assignment of {display_discr_i}"));
err.span_label(span, format!("second assignment of {display_discr}"));

if no_disr {
err.span_label(
prev_variant_span,
format!(
"assigned discriminant for `{}` was incremented from this discriminant",
v.ident
),
);
}
err.emit();
}

disr_vals.push(discr);
prev_variant_span = v.span;
}

check_representable(tcx, sp, def_id);
check_transparent(tcx, sp, def);
}

/// Format an enum discriminant value for use in a diagnostic message.
fn display_discriminant_value<'tcx>(
/// In the case that a discriminant is both a duplicate and an overflowing literal,
/// we insert both the assigned discriminant and the literal it overflowed from into the formatted
/// output. Otherwise we format the discriminant normally.
fn format_discriminant_overflow<'tcx>(
tcx: TyCtxt<'tcx>,
variant: &hir::Variant<'_>,
evaluated: u128,
dis: Discr<'tcx>,
) -> String {
if let Some(expr) = &variant.disr_expr {
let body = &tcx.hir().body(expr.body).value;
if let hir::ExprKind::Lit(lit) = &body.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& evaluated != *lit_value
&& dis.val != *lit_value
{
return format!("`{evaluated}` (overflowed from `{lit_value}`)");
return format!("`{dis}` (overflowed from `{lit_value}`)");
}
}
format!("`{}`", evaluated)

format!("`{dis}`")
}

pub(super) fn check_type_params_are_used<'tcx>(
Expand Down
7 changes: 4 additions & 3 deletions src/test/ui/enum/enum-discrim-autosizing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
// so force the repr.
#[cfg_attr(not(target_pointer_width = "32"), repr(i32))]
enum Eu64 {
Au64 = 0, //~NOTE first use of `0`
//~^ ERROR discriminant value `0` assigned more than once
Au64 = 0,
//~^NOTE first assignment of `0`
Bu64 = 0x8000_0000_0000_0000
//~^ ERROR discriminant value `0` already exists
//~| NOTE enum already has `0` (overflowed from `9223372036854775808`)
//~^NOTE second assignment of `0` (overflowed from `9223372036854775808`)
}

fn main() {}
18 changes: 12 additions & 6 deletions src/test/ui/enum/enum-discrim-autosizing.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
error[E0081]: discriminant value `0` already exists
--> $DIR/enum-discrim-autosizing.rs:8:12
error[E0081]: discriminant value `0` assigned more than once
--> $DIR/enum-discrim-autosizing.rs:6:1
|
LL | Au64 = 0,
| - first use of `0`
LL | Bu64 = 0x8000_0000_0000_0000
| ^^^^^^^^^^^^^^^^^^^^^ enum already has `0` (overflowed from `9223372036854775808`)
LL | / enum Eu64 {
LL | |
LL | | Au64 = 0,
| | - first assignment of `0`
LL | |
LL | | Bu64 = 0x8000_0000_0000_0000
| | --------------------- second assignment of `0` (overflowed from `9223372036854775808`)
LL | |
LL | | }
| |_^

error: aborting due to previous error

Expand Down
23 changes: 17 additions & 6 deletions src/test/ui/error-codes/E0081.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
enum Enum {
//~^ ERROR discriminant value `3` assigned more than once
P = 3,
//~^ NOTE first use of `3`
//~^ NOTE first assignment of `3`
X = 3,
//~^ ERROR discriminant value `3` already exists
//~| NOTE enum already has `3`
//~^ NOTE second assignment of `3`
Y = 5
}

#[repr(u8)]
enum EnumOverflowRepr {
//~^ ERROR discriminant value `1` assigned more than once
P = 257,
//~^ NOTE first use of `1` (overflowed from `257`)
//~^ NOTE first assignment of `1` (overflowed from `257`)
X = 513,
//~^ ERROR discriminant value `1` already exists
//~| NOTE enum already has `1` (overflowed from `513`)
//~^ NOTE second assignment of `1` (overflowed from `513`)
}

#[repr(i8)]
enum NegDisEnum {
//~^ ERROR discriminant value `-1` assigned more than once
First = -1,
//~^ NOTE first assignment of `-1`
Second = -2,
//~^ NOTE assigned discriminant for `Last` was incremented from this discriminant
Last,
//~^ NOTE second assignment of `-1`
}

fn main() {
Expand Down
58 changes: 43 additions & 15 deletions src/test/ui/error-codes/E0081.stderr
Original file line number Diff line number Diff line change
@@ -1,21 +1,49 @@
error[E0081]: discriminant value `3` already exists
--> $DIR/E0081.rs:4:9
error[E0081]: discriminant value `3` assigned more than once
--> $DIR/E0081.rs:1:1
|
LL | P = 3,
| - first use of `3`
LL |
LL | X = 3,
| ^ enum already has `3`
LL | / enum Enum {
LL | |
LL | | P = 3,
| | - first assignment of `3`
LL | |
LL | | X = 3,
| | - second assignment of `3`
LL | |
LL | | Y = 5
LL | | }
| |_^

error[E0081]: discriminant value `1` already exists
--> $DIR/E0081.rs:14:9
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/E0081.rs:11:1
|
LL | P = 257,
| --- first use of `1` (overflowed from `257`)
LL |
LL | X = 513,
| ^^^ enum already has `1` (overflowed from `513`)
LL | / enum EnumOverflowRepr {
LL | |
LL | | P = 257,
| | --- first assignment of `1` (overflowed from `257`)
LL | |
LL | | X = 513,
| | --- second assignment of `1` (overflowed from `513`)
LL | |
LL | | }
| |_^

error: aborting due to 2 previous errors
error[E0081]: discriminant value `-1` assigned more than once
--> $DIR/E0081.rs:20:1
|
LL | / enum NegDisEnum {
LL | |
LL | | First = -1,
| | -- first assignment of `-1`
LL | |
LL | | Second = -2,
| | ----------- assigned discriminant for `Last` was incremented from this discriminant
LL | |
LL | | Last,
| | ---- second assignment of `-1`
LL | |
LL | | }
| |_^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0081`.
6 changes: 3 additions & 3 deletions src/test/ui/issues/issue-15524.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
const N: isize = 1;

enum Foo {
//~^ ERROR discriminant value `1` assigned more than once
//~| ERROR discriminant value `1` assigned more than once
//~| ERROR discriminant value `1` assigned more than once
A = 1,
B = 1,
//~^ ERROR discriminant value `1` already exists
C = 0,
D,
//~^ ERROR discriminant value `1` already exists

E = N,
//~^ ERROR discriminant value `1` already exists

}

Expand Down
65 changes: 45 additions & 20 deletions src/test/ui/issues/issue-15524.stderr
Original file line number Diff line number Diff line change
@@ -1,28 +1,53 @@
error[E0081]: discriminant value `1` already exists
--> $DIR/issue-15524.rs:5:9
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | A = 1,
| - first use of `1`
LL | B = 1,
| ^ enum already has `1`
LL | / enum Foo {
LL | |
LL | |
LL | |
LL | | A = 1,
| | - first assignment of `1`
LL | | B = 1,
| | - second assignment of `1`
... |
LL | |
LL | | }
| |_^

error[E0081]: discriminant value `1` already exists
--> $DIR/issue-15524.rs:8:5
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | A = 1,
| - first use of `1`
...
LL | D,
| ^ enum already has `1`
LL | / enum Foo {
LL | |
LL | |
LL | |
LL | | A = 1,
| | - first assignment of `1`
LL | | B = 1,
LL | | C = 0,
| | ----- assigned discriminant for `D` was incremented from this discriminant
LL | | D,
| | - second assignment of `1`
... |
LL | |
LL | | }
| |_^

error[E0081]: discriminant value `1` already exists
--> $DIR/issue-15524.rs:11:9
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | A = 1,
| - first use of `1`
...
LL | E = N,
| ^ enum already has `1`
LL | / enum Foo {
LL | |
LL | |
LL | |
LL | | A = 1,
| | - first assignment of `1`
... |
LL | | E = N,
| | - second assignment of `1`
LL | |
LL | | }
| |_^

error: aborting due to 3 previous errors

Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/tag-variant-disr-dup.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Black and White have the same discriminator value ...

enum Color {
//~^ ERROR discriminant value `0` assigned more than once
Red = 0xff0000,
Green = 0x00ff00,
Blue = 0x0000ff,
Black = 0x000000,
White = 0x000000, //~ ERROR discriminant value `0` already exists
White = 0x000000,
}

fn main() { }
19 changes: 13 additions & 6 deletions src/test/ui/tag-variant-disr-dup.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
error[E0081]: discriminant value `0` already exists
--> $DIR/tag-variant-disr-dup.rs:8:13
error[E0081]: discriminant value `0` assigned more than once
--> $DIR/tag-variant-disr-dup.rs:3:1
|
LL | Black = 0x000000,
| -------- first use of `0`
LL | White = 0x000000,
| ^^^^^^^^ enum already has `0`
LL | / enum Color {
LL | |
LL | | Red = 0xff0000,
LL | | Green = 0x00ff00,
LL | | Blue = 0x0000ff,
LL | | Black = 0x000000,
| | -------- first assignment of `0`
LL | | White = 0x000000,
| | -------- second assignment of `0`
LL | | }
| |_^

error: aborting due to previous error

Expand Down