@@ -35,6 +35,7 @@ use crate::type_error_struct;
35
35
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
36
36
use rustc_hir as hir;
37
37
use rustc_hir:: lang_items:: LangItem ;
38
+ use rustc_middle:: mir:: Mutability ;
38
39
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
39
40
use rustc_middle:: ty:: cast:: { CastKind , CastTy } ;
40
41
use rustc_middle:: ty:: error:: TypeError ;
@@ -347,15 +348,52 @@ impl<'a, 'tcx> CastCheck<'tcx> {
347
348
fcx. ty_to_string( self . cast_ty)
348
349
) ;
349
350
let mut sugg = None ;
351
+ let mut sugg_mutref = false ;
350
352
if let ty:: Ref ( reg, _, mutbl) = * self . cast_ty . kind ( ) {
351
- if fcx
352
- . try_coerce (
353
- self . expr ,
354
- fcx. tcx . mk_ref ( reg, TypeAndMut { ty : self . expr_ty , mutbl } ) ,
355
- self . cast_ty ,
356
- AllowTwoPhase :: No ,
357
- )
358
- . is_ok ( )
353
+ if let ty:: RawPtr ( TypeAndMut { ty : expr_ty, .. } ) = * self . expr_ty . kind ( ) {
354
+ if fcx
355
+ . try_coerce (
356
+ self . expr ,
357
+ fcx. tcx . mk_ref (
358
+ & ty:: RegionKind :: ReErased ,
359
+ TypeAndMut { ty : expr_ty, mutbl } ,
360
+ ) ,
361
+ self . cast_ty ,
362
+ AllowTwoPhase :: No ,
363
+ )
364
+ . is_ok ( )
365
+ {
366
+ sugg = Some ( format ! ( "&{}*" , mutbl. prefix_str( ) ) ) ;
367
+ }
368
+ } else if let ty:: Ref ( expr_reg, expr_ty, expr_mutbl) = * self . expr_ty . kind ( ) {
369
+ if expr_mutbl == Mutability :: Not
370
+ && mutbl == Mutability :: Mut
371
+ && fcx
372
+ . try_coerce (
373
+ self . expr ,
374
+ fcx. tcx . mk_ref (
375
+ expr_reg,
376
+ TypeAndMut { ty : expr_ty, mutbl : Mutability :: Mut } ,
377
+ ) ,
378
+ self . cast_ty ,
379
+ AllowTwoPhase :: No ,
380
+ )
381
+ . is_ok ( )
382
+ {
383
+ sugg_mutref = true ;
384
+ }
385
+ }
386
+
387
+ if !sugg_mutref
388
+ && sugg == None
389
+ && fcx
390
+ . try_coerce (
391
+ self . expr ,
392
+ fcx. tcx . mk_ref ( reg, TypeAndMut { ty : self . expr_ty , mutbl } ) ,
393
+ self . cast_ty ,
394
+ AllowTwoPhase :: No ,
395
+ )
396
+ . is_ok ( )
359
397
{
360
398
sugg = Some ( format ! ( "&{}" , mutbl. prefix_str( ) ) ) ;
361
399
}
@@ -375,11 +413,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
375
413
sugg = Some ( format ! ( "&{}" , mutbl. prefix_str( ) ) ) ;
376
414
}
377
415
}
378
- if let Some ( sugg) = sugg {
416
+ if sugg_mutref {
417
+ err. span_label ( self . span , "invalid cast" ) ;
418
+ err. span_note ( self . expr . span , "this reference is immutable" ) ;
419
+ err. span_note ( self . cast_span , "trying to cast to a mutable reference type" ) ;
420
+ } else if let Some ( sugg) = sugg {
379
421
err. span_label ( self . span , "invalid cast" ) ;
380
422
err. span_suggestion_verbose (
381
423
self . expr . span . shrink_to_lo ( ) ,
382
- "borrow the value for the cast to be valid " ,
424
+ "consider borrowing the value " ,
383
425
sugg,
384
426
Applicability :: MachineApplicable ,
385
427
) ;
0 commit comments