@@ -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
14311450pub ( super ) fn check_type_params_are_used < ' tcx > (
0 commit comments