@@ -663,6 +663,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
663
663
return ;
664
664
}
665
665
let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
666
+
666
667
let ( post_message, pre_message, type_def) = self
667
668
. get_parent_trait_ref ( obligation. cause . code ( ) )
668
669
. map ( |( t, s) | {
@@ -702,33 +703,45 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
702
703
( message, note, append_const_msg)
703
704
} ;
704
705
705
- let mut err = struct_span_err ! (
706
- self . tcx. sess,
707
- span,
708
- E0277 ,
709
- "{}" ,
710
- message
711
- . and_then( |cannot_do_this| {
712
- match ( predicate_is_const, append_const_msg) {
713
- // do nothing if predicate is not const
714
- ( false , _) => Some ( cannot_do_this) ,
715
- // suggested using default post message
716
- ( true , Some ( None ) ) => {
717
- Some ( format!( "{cannot_do_this} in const contexts" ) )
718
- }
719
- // overridden post message
720
- ( true , Some ( Some ( post_message) ) ) => {
721
- Some ( format!( "{cannot_do_this}{post_message}" ) )
722
- }
723
- // fallback to generic message
724
- ( true , None ) => None ,
706
+ let err_msg = message
707
+ . and_then ( |cannot_do_this| {
708
+ match ( predicate_is_const, append_const_msg) {
709
+ // do nothing if predicate is not const
710
+ ( false , _) => Some ( cannot_do_this) ,
711
+ // suggested using default post message
712
+ ( true , Some ( None ) ) => {
713
+ Some ( format ! ( "{cannot_do_this} in const contexts" ) )
714
+ }
715
+ // overridden post message
716
+ ( true , Some ( Some ( post_message) ) ) => {
717
+ Some ( format ! ( "{cannot_do_this}{post_message}" ) )
725
718
}
726
- } )
727
- . unwrap_or_else( || format!(
719
+ // fallback to generic message
720
+ ( true , None ) => None ,
721
+ }
722
+ } )
723
+ . unwrap_or_else ( || {
724
+ format ! (
728
725
"the trait bound `{}` is not satisfied{}" ,
729
726
trait_predicate, post_message,
730
- ) )
731
- ) ;
727
+ )
728
+ } ) ;
729
+
730
+ let ( err_msg, safe_transmute_explanation) = if Some ( trait_ref. def_id ( ) )
731
+ == self . tcx . lang_items ( ) . transmute_trait ( )
732
+ {
733
+ // Recompute the safe transmute reason and use that for the error reporting
734
+ self . get_safe_transmute_error_and_reason (
735
+ trait_predicate,
736
+ obligation. clone ( ) ,
737
+ trait_ref,
738
+ span,
739
+ )
740
+ } else {
741
+ ( err_msg, None )
742
+ } ;
743
+
744
+ let mut err = struct_span_err ! ( self . tcx. sess, span, E0277 , "{}" , err_msg) ;
732
745
733
746
if is_try_conversion && let Some ( ret_span) = self . return_type_span ( & obligation) {
734
747
err. span_label (
@@ -818,6 +831,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
818
831
// at the type param with a label to suggest constraining it.
819
832
err. help ( & explanation) ;
820
833
}
834
+ } else if let Some ( custom_explanation) = safe_transmute_explanation {
835
+ err. span_label ( span, custom_explanation) ;
821
836
} else {
822
837
err. span_label ( span, explanation) ;
823
838
}
@@ -1601,6 +1616,14 @@ trait InferCtxtPrivExt<'tcx> {
1601
1616
obligated_types : & mut Vec < Ty < ' tcx > > ,
1602
1617
cause_code : & ObligationCauseCode < ' tcx > ,
1603
1618
) -> bool ;
1619
+
1620
+ fn get_safe_transmute_error_and_reason (
1621
+ & self ,
1622
+ trait_predicate : ty:: Binder < ' tcx , ty:: TraitPredicate < ' tcx > > ,
1623
+ obligation : Obligation < ' tcx , ty:: Predicate < ' tcx > > ,
1624
+ trait_ref : ty:: Binder < ' tcx , ty:: TraitRef < ' tcx > > ,
1625
+ span : Span ,
1626
+ ) -> ( String , Option < String > ) ;
1604
1627
}
1605
1628
1606
1629
impl < ' tcx > InferCtxtPrivExt < ' tcx > for TypeErrCtxt < ' _ , ' tcx > {
@@ -2879,6 +2902,63 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
2879
2902
}
2880
2903
false
2881
2904
}
2905
+
2906
+ fn get_safe_transmute_error_and_reason (
2907
+ & self ,
2908
+ trait_predicate : ty:: Binder < ' tcx , ty:: TraitPredicate < ' tcx > > ,
2909
+ obligation : Obligation < ' tcx , ty:: Predicate < ' tcx > > ,
2910
+ trait_ref : ty:: Binder < ' tcx , ty:: TraitRef < ' tcx > > ,
2911
+ span : Span ,
2912
+ ) -> ( String , Option < String > ) {
2913
+ let src_and_dst = trait_predicate. map_bound ( |p| rustc_transmute:: Types {
2914
+ dst : p. trait_ref . substs . type_at ( 0 ) ,
2915
+ src : p. trait_ref . substs . type_at ( 1 ) ,
2916
+ } ) ;
2917
+ let scope = trait_ref. skip_binder ( ) . substs . type_at ( 2 ) ;
2918
+ let Some ( assume) =
2919
+ rustc_transmute:: Assume :: from_const ( self . infcx . tcx , obligation. param_env , trait_ref. skip_binder ( ) . substs . const_at ( 3 ) ) else {
2920
+ span_bug ! ( span, "Unable to construct rustc_transmute::Assume where it was previously possible" ) ;
2921
+ } ;
2922
+ match rustc_transmute:: TransmuteTypeEnv :: new ( self . infcx ) . is_transmutable (
2923
+ obligation. cause ,
2924
+ src_and_dst,
2925
+ scope,
2926
+ assume,
2927
+ ) {
2928
+ rustc_transmute:: Answer :: No ( reason) => {
2929
+ let dst = trait_ref. skip_binder ( ) . substs . type_at ( 0 ) ;
2930
+ let src = trait_ref. skip_binder ( ) . substs . type_at ( 1 ) ;
2931
+ let custom_err_msg = format ! ( "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`" ) . to_string ( ) ;
2932
+ let reason_msg = match reason {
2933
+ rustc_transmute:: Reason :: SrcIsUnspecified => {
2934
+ format ! ( "`{src}` does not have a well-specified layout" ) . to_string ( )
2935
+ }
2936
+ rustc_transmute:: Reason :: DstIsUnspecified => {
2937
+ format ! ( "`{dst}` does not have a well-specified layout" ) . to_string ( )
2938
+ }
2939
+ rustc_transmute:: Reason :: DstIsBitIncompatible => {
2940
+ format ! ( "At least one value of `{src}` isn't a bit-valid value of `{dst}`" )
2941
+ . to_string ( )
2942
+ }
2943
+ rustc_transmute:: Reason :: DstIsPrivate => format ! (
2944
+ "`{dst}` is or contains a type or field that is not visible in that scope"
2945
+ )
2946
+ . to_string ( ) ,
2947
+ // FIXME(bryangarza): Include the number of bytes of src and dst
2948
+ rustc_transmute:: Reason :: DstIsTooBig => {
2949
+ format ! ( "The size of `{src}` is smaller than the size of `{dst}`" )
2950
+ }
2951
+ } ;
2952
+ ( custom_err_msg, Some ( reason_msg) )
2953
+ }
2954
+ // Should never get a Yes at this point! We already ran it before, and did not get a Yes.
2955
+ rustc_transmute:: Answer :: Yes => span_bug ! (
2956
+ span,
2957
+ "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes" ,
2958
+ ) ,
2959
+ _ => span_bug ! ( span, "Unsupported rustc_transmute::Reason variant" ) ,
2960
+ }
2961
+ }
2882
2962
}
2883
2963
2884
2964
/// Crude way of getting back an `Expr` from a `Span`.
0 commit comments