@@ -1376,6 +1376,8 @@ fn check_enum<'tcx>(
1376
1376
}
1377
1377
1378
1378
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 ;
1379
1381
for ( ( _, discr) , v) in iter:: zip ( def. discriminants ( tcx) , vs) {
1380
1382
// Check for duplicate discriminant values
1381
1383
if let Some ( i) = disr_vals. iter ( ) . position ( |& x| x. val == discr. val ) {
@@ -1390,42 +1392,59 @@ fn check_enum<'tcx>(
1390
1392
Some ( ref expr) => tcx. hir ( ) . span ( expr. hir_id ) ,
1391
1393
None => v. span ,
1392
1394
} ;
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 ! (
1396
1399
tcx. sess,
1397
- span ,
1400
+ sp ,
1398
1401
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 ( ) ;
1405
1419
}
1420
+
1406
1421
disr_vals. push ( discr) ;
1422
+ prev_variant_span = v. span ;
1407
1423
}
1408
1424
1409
1425
check_representable ( tcx, sp, def_id) ;
1410
1426
check_transparent ( tcx, sp, def) ;
1411
1427
}
1412
1428
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 > (
1415
1433
tcx : TyCtxt < ' tcx > ,
1416
1434
variant : & hir:: Variant < ' _ > ,
1417
- evaluated : u128 ,
1435
+ dis : Discr < ' tcx > ,
1418
1436
) -> String {
1419
1437
if let Some ( expr) = & variant. disr_expr {
1420
1438
let body = & tcx. hir ( ) . body ( expr. body ) . value ;
1421
1439
if let hir:: ExprKind :: Lit ( lit) = & body. kind
1422
1440
&& let rustc_ast:: LitKind :: Int ( lit_value, _int_kind) = & lit. node
1423
- && evaluated != * lit_value
1441
+ && dis . val != * lit_value
1424
1442
{
1425
- return format ! ( "`{evaluated }` (overflowed from `{lit_value}`)" ) ;
1443
+ return format ! ( "`{dis }` (overflowed from `{lit_value}`)" ) ;
1426
1444
}
1427
1445
}
1428
- format ! ( "`{}`" , evaluated)
1446
+
1447
+ format ! ( "`{dis}`" )
1429
1448
}
1430
1449
1431
1450
pub ( super ) fn check_type_params_are_used < ' tcx > (
0 commit comments