@@ -35,6 +35,7 @@ use crate::type_error_struct;
3535use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
3636use rustc_hir as hir;
3737use rustc_hir:: lang_items:: LangItem ;
38+ use rustc_middle:: mir:: Mutability ;
3839use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
3940use rustc_middle:: ty:: cast:: { CastKind , CastTy } ;
4041use rustc_middle:: ty:: error:: TypeError ;
@@ -347,15 +348,52 @@ impl<'a, 'tcx> CastCheck<'tcx> {
347348 fcx. ty_to_string( self . cast_ty)
348349 ) ;
349350 let mut sugg = None ;
351+ let mut sugg_mutref = false ;
350352 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 ( )
359397 {
360398 sugg = Some ( format ! ( "&{}" , mutbl. prefix_str( ) ) ) ;
361399 }
@@ -375,11 +413,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
375413 sugg = Some ( format ! ( "&{}" , mutbl. prefix_str( ) ) ) ;
376414 }
377415 }
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 {
379421 err. span_label ( self . span , "invalid cast" ) ;
380422 err. span_suggestion_verbose (
381423 self . expr . span . shrink_to_lo ( ) ,
382- "borrow the value for the cast to be valid " ,
424+ "consider borrowing the value " ,
383425 sugg,
384426 Applicability :: MachineApplicable ,
385427 ) ;
0 commit comments