@@ -7,7 +7,7 @@ use rustc_hir as hir;
77use rustc_index:: Idx ;
88use rustc_middle:: bug;
99use rustc_middle:: ty:: layout:: { LayoutError , SizeSkeleton } ;
10- use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitableExt } ;
10+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1111use rustc_span:: def_id:: LocalDefId ;
1212use tracing:: trace;
1313
@@ -38,58 +38,86 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
3838 ty
3939}
4040
41+ /// Try to display a sensible error with as much information as possible.
42+ fn skeleton_string < ' tcx > (
43+ ty : Ty < ' tcx > ,
44+ sk : Result < SizeSkeleton < ' tcx > , & ' tcx LayoutError < ' tcx > > ,
45+ ) -> String {
46+ match sk {
47+ Ok ( SizeSkeleton :: Pointer { tail, .. } ) => format ! ( "pointer to `{tail}`" ) ,
48+ Ok ( SizeSkeleton :: Known ( size, _) ) => {
49+ if let Some ( v) = u128:: from ( size. bytes ( ) ) . checked_mul ( 8 ) {
50+ format ! ( "{v} bits" )
51+ } else {
52+ // `u128` should definitely be able to hold the size of different architectures
53+ // larger sizes should be reported as error `are too big for the target architecture`
54+ // otherwise we have a bug somewhere
55+ bug ! ( "{:?} overflow for u128" , size)
56+ }
57+ }
58+ Ok ( SizeSkeleton :: Generic ( size) ) => {
59+ format ! ( "generic size {size}" )
60+ }
61+ Err ( LayoutError :: TooGeneric ( bad) ) => {
62+ if * bad == ty {
63+ "this type does not have a fixed size" . to_owned ( )
64+ } else {
65+ format ! ( "size can vary because of {bad}" )
66+ }
67+ }
68+ Err ( err) => err. to_string ( ) ,
69+ }
70+ }
71+
4172fn check_transmute < ' tcx > (
4273 tcx : TyCtxt < ' tcx > ,
4374 typing_env : ty:: TypingEnv < ' tcx > ,
4475 from : Ty < ' tcx > ,
4576 to : Ty < ' tcx > ,
4677 hir_id : HirId ,
4778) {
48- let dl = & tcx. data_layout ;
49- let span = tcx. hir_span ( hir_id) ;
79+ let span = || tcx. hir_span ( hir_id) ;
5080 let normalize = |ty| {
5181 if let Ok ( ty) = tcx. try_normalize_erasing_regions ( typing_env, ty) {
5282 ty
5383 } else {
5484 Ty :: new_error_with_message (
5585 tcx,
56- span,
86+ span ( ) ,
5787 format ! ( "tried to normalize non-wf type {ty:#?} in check_transmute" ) ,
5888 )
5989 }
6090 } ;
91+
6192 let from = normalize ( from) ;
6293 let to = normalize ( to) ;
6394 trace ! ( ?from, ?to) ;
64- if from. has_non_region_infer ( ) || to. has_non_region_infer ( ) {
65- // Note: this path is currently not reached in any test, so any
66- // example that triggers this would be worth minimizing and
67- // converting into a test.
68- tcx. sess . dcx ( ) . span_bug ( span, "argument to transmute has inference variables" ) ;
69- }
95+
7096 // Transmutes that are only changing lifetimes are always ok.
7197 if from == to {
7298 return ;
7399 }
74100
75- let skel = |ty| SizeSkeleton :: compute ( ty, tcx, typing_env) ;
76- let sk_from = skel ( from) ;
77- let sk_to = skel ( to) ;
101+ let sk_from = SizeSkeleton :: compute ( from, tcx, typing_env) ;
102+ let sk_to = SizeSkeleton :: compute ( to, tcx, typing_env) ;
78103 trace ! ( ?sk_from, ?sk_to) ;
79104
80105 // Check for same size using the skeletons.
81- if let ( Ok ( sk_from) , Ok ( sk_to) ) = ( sk_from, sk_to) {
106+ if let Ok ( sk_from) = sk_from
107+ && let Ok ( sk_to) = sk_to
108+ {
82109 if sk_from. same_size ( sk_to) {
83110 return ;
84111 }
85112
86113 // Special-case transmuting from `typeof(function)` and
87114 // `Option<typeof(function)>` to present a clearer error.
88115 let from = unpack_option_like ( tcx, from) ;
89- if let ( & ty:: FnDef ( ..) , SizeSkeleton :: Known ( size_to, _) ) = ( from. kind ( ) , sk_to)
90- && size_to == Pointer ( dl. instruction_address_space ) . size ( & tcx)
116+ if let ty:: FnDef ( ..) = from. kind ( )
117+ && let SizeSkeleton :: Known ( size_to, _) = sk_to
118+ && size_to == Pointer ( tcx. data_layout . instruction_address_space ) . size ( & tcx)
91119 {
92- struct_span_code_err ! ( tcx. sess. dcx( ) , span, E0591 , "can't transmute zero-sized type" )
120+ struct_span_code_err ! ( tcx. sess. dcx( ) , span( ) , E0591 , "can't transmute zero-sized type" )
93121 . with_note ( format ! ( "source type: {from}" ) )
94122 . with_note ( format ! ( "target type: {to}" ) )
95123 . with_help ( "cast with `as` to a pointer instead" )
@@ -98,35 +126,9 @@ fn check_transmute<'tcx>(
98126 }
99127 }
100128
101- // Try to display a sensible error with as much information as possible.
102- let skeleton_string = |ty : Ty < ' tcx > , sk : Result < _ , & _ > | match sk {
103- Ok ( SizeSkeleton :: Pointer { tail, .. } ) => format ! ( "pointer to `{tail}`" ) ,
104- Ok ( SizeSkeleton :: Known ( size, _) ) => {
105- if let Some ( v) = u128:: from ( size. bytes ( ) ) . checked_mul ( 8 ) {
106- format ! ( "{v} bits" )
107- } else {
108- // `u128` should definitely be able to hold the size of different architectures
109- // larger sizes should be reported as error `are too big for the target architecture`
110- // otherwise we have a bug somewhere
111- bug ! ( "{:?} overflow for u128" , size)
112- }
113- }
114- Ok ( SizeSkeleton :: Generic ( size) ) => {
115- format ! ( "generic size {size}" )
116- }
117- Err ( LayoutError :: TooGeneric ( bad) ) => {
118- if * bad == ty {
119- "this type does not have a fixed size" . to_owned ( )
120- } else {
121- format ! ( "size can vary because of {bad}" )
122- }
123- }
124- Err ( err) => err. to_string ( ) ,
125- } ;
126-
127129 let mut err = struct_span_code_err ! (
128130 tcx. sess. dcx( ) ,
129- span,
131+ span( ) ,
130132 E0512 ,
131133 "cannot transmute between types of different sizes, or dependently-sized types"
132134 ) ;
0 commit comments