@@ -673,6 +673,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
673
673
return ;
674
674
}
675
675
let trait_ref = trait_predicate. to_poly_trait_ref ( ) ;
676
+
676
677
let ( post_message, pre_message, type_def) = self
677
678
. get_parent_trait_ref ( obligation. cause . code ( ) )
678
679
. map ( |( t, s) | {
@@ -712,33 +713,45 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
712
713
( message, note, append_const_msg)
713
714
} ;
714
715
715
- let mut err = struct_span_err ! (
716
- self . tcx. sess,
717
- span,
718
- E0277 ,
719
- "{}" ,
720
- message
721
- . and_then( |cannot_do_this| {
722
- match ( predicate_is_const, append_const_msg) {
723
- // do nothing if predicate is not const
724
- ( false , _) => Some ( cannot_do_this) ,
725
- // suggested using default post message
726
- ( true , Some ( None ) ) => {
727
- Some ( format!( "{cannot_do_this} in const contexts" ) )
728
- }
729
- // overridden post message
730
- ( true , Some ( Some ( post_message) ) ) => {
731
- Some ( format!( "{cannot_do_this}{post_message}" ) )
732
- }
733
- // fallback to generic message
734
- ( true , None ) => None ,
716
+ let err_msg = message
717
+ . and_then ( |cannot_do_this| {
718
+ match ( predicate_is_const, append_const_msg) {
719
+ // do nothing if predicate is not const
720
+ ( false , _) => Some ( cannot_do_this) ,
721
+ // suggested using default post message
722
+ ( true , Some ( None ) ) => {
723
+ Some ( format ! ( "{cannot_do_this} in const contexts" ) )
724
+ }
725
+ // overridden post message
726
+ ( true , Some ( Some ( post_message) ) ) => {
727
+ Some ( format ! ( "{cannot_do_this}{post_message}" ) )
735
728
}
736
- } )
737
- . unwrap_or_else( || format!(
729
+ // fallback to generic message
730
+ ( true , None ) => None ,
731
+ }
732
+ } )
733
+ . unwrap_or_else ( || {
734
+ format ! (
738
735
"the trait bound `{}` is not satisfied{}" ,
739
736
trait_predicate, post_message,
740
- ) )
741
- ) ;
737
+ )
738
+ } ) ;
739
+
740
+ let ( err_msg, safe_transmute_explanation) = if Some ( trait_ref. def_id ( ) )
741
+ == self . tcx . lang_items ( ) . transmute_trait ( )
742
+ {
743
+ // Recompute the safe transmute reason and use that for the error reporting
744
+ self . get_safe_transmute_error_and_reason (
745
+ trait_predicate,
746
+ obligation. clone ( ) ,
747
+ trait_ref,
748
+ span,
749
+ )
750
+ } else {
751
+ ( err_msg, None )
752
+ } ;
753
+
754
+ let mut err = struct_span_err ! ( self . tcx. sess, span, E0277 , "{}" , err_msg) ;
742
755
743
756
if is_try_conversion && let Some ( ret_span) = self . return_type_span ( & obligation) {
744
757
err. span_label (
@@ -828,6 +841,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
828
841
// at the type param with a label to suggest constraining it.
829
842
err. help ( & explanation) ;
830
843
}
844
+ } else if let Some ( custom_explanation) = safe_transmute_explanation {
845
+ err. span_label ( span, custom_explanation) ;
831
846
} else {
832
847
err. span_label ( span, explanation) ;
833
848
}
@@ -1611,6 +1626,14 @@ trait InferCtxtPrivExt<'tcx> {
1611
1626
obligated_types : & mut Vec < Ty < ' tcx > > ,
1612
1627
cause_code : & ObligationCauseCode < ' tcx > ,
1613
1628
) -> bool ;
1629
+
1630
+ fn get_safe_transmute_error_and_reason (
1631
+ & self ,
1632
+ trait_predicate : ty:: Binder < ' tcx , ty:: TraitPredicate < ' tcx > > ,
1633
+ obligation : Obligation < ' tcx , ty:: Predicate < ' tcx > > ,
1634
+ trait_ref : ty:: Binder < ' tcx , ty:: TraitRef < ' tcx > > ,
1635
+ span : Span ,
1636
+ ) -> ( String , Option < String > ) ;
1614
1637
}
1615
1638
1616
1639
impl < ' tcx > InferCtxtPrivExt < ' tcx > for TypeErrCtxt < ' _ , ' tcx > {
@@ -2895,6 +2918,63 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
2895
2918
}
2896
2919
false
2897
2920
}
2921
+
2922
+ fn get_safe_transmute_error_and_reason (
2923
+ & self ,
2924
+ trait_predicate : ty:: Binder < ' tcx , ty:: TraitPredicate < ' tcx > > ,
2925
+ obligation : Obligation < ' tcx , ty:: Predicate < ' tcx > > ,
2926
+ trait_ref : ty:: Binder < ' tcx , ty:: TraitRef < ' tcx > > ,
2927
+ span : Span ,
2928
+ ) -> ( String , Option < String > ) {
2929
+ let src_and_dst = trait_predicate. map_bound ( |p| rustc_transmute:: Types {
2930
+ dst : p. trait_ref . substs . type_at ( 0 ) ,
2931
+ src : p. trait_ref . substs . type_at ( 1 ) ,
2932
+ } ) ;
2933
+ let scope = trait_ref. skip_binder ( ) . substs . type_at ( 2 ) ;
2934
+ let Some ( assume) =
2935
+ rustc_transmute:: Assume :: from_const ( self . infcx . tcx , obligation. param_env , trait_ref. skip_binder ( ) . substs . const_at ( 3 ) ) else {
2936
+ span_bug ! ( span, "Unable to construct rustc_transmute::Assume where it was previously possible" ) ;
2937
+ } ;
2938
+ match rustc_transmute:: TransmuteTypeEnv :: new ( self . infcx ) . is_transmutable (
2939
+ obligation. cause ,
2940
+ src_and_dst,
2941
+ scope,
2942
+ assume,
2943
+ ) {
2944
+ rustc_transmute:: Answer :: No ( reason) => {
2945
+ let dst = trait_ref. skip_binder ( ) . substs . type_at ( 0 ) ;
2946
+ let src = trait_ref. skip_binder ( ) . substs . type_at ( 1 ) ;
2947
+ let custom_err_msg = format ! ( "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`" ) . to_string ( ) ;
2948
+ let reason_msg = match reason {
2949
+ rustc_transmute:: Reason :: SrcIsUnspecified => {
2950
+ format ! ( "`{src}` does not have a well-specified layout" ) . to_string ( )
2951
+ }
2952
+ rustc_transmute:: Reason :: DstIsUnspecified => {
2953
+ format ! ( "`{dst}` does not have a well-specified layout" ) . to_string ( )
2954
+ }
2955
+ rustc_transmute:: Reason :: DstIsBitIncompatible => {
2956
+ format ! ( "At least one value of `{src}` isn't a bit-valid value of `{dst}`" )
2957
+ . to_string ( )
2958
+ }
2959
+ rustc_transmute:: Reason :: DstIsPrivate => format ! (
2960
+ "`{dst}` is or contains a type or field that is not visible in that scope"
2961
+ )
2962
+ . to_string ( ) ,
2963
+ // FIXME(bryangarza): Include the number of bytes of src and dst
2964
+ rustc_transmute:: Reason :: DstIsTooBig => {
2965
+ format ! ( "The size of `{src}` is smaller than the size of `{dst}`" )
2966
+ }
2967
+ } ;
2968
+ ( custom_err_msg, Some ( reason_msg) )
2969
+ }
2970
+ // Should never get a Yes at this point! We already ran it before, and did not get a Yes.
2971
+ rustc_transmute:: Answer :: Yes => span_bug ! (
2972
+ span,
2973
+ "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes" ,
2974
+ ) ,
2975
+ _ => span_bug ! ( span, "Unsupported rustc_transmute::Reason variant" ) ,
2976
+ }
2977
+ }
2898
2978
}
2899
2979
2900
2980
/// Crude way of getting back an `Expr` from a `Span`.
0 commit comments