@@ -7,7 +7,7 @@ use rustc_hir as hir;
7
7
use rustc_index:: Idx ;
8
8
use rustc_middle:: bug;
9
9
use rustc_middle:: ty:: layout:: { LayoutError , SizeSkeleton } ;
10
- use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitableExt } ;
10
+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
11
11
use rustc_span:: def_id:: LocalDefId ;
12
12
use tracing:: trace;
13
13
@@ -38,58 +38,86 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
38
38
ty
39
39
}
40
40
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
+
41
72
fn check_transmute < ' tcx > (
42
73
tcx : TyCtxt < ' tcx > ,
43
74
typing_env : ty:: TypingEnv < ' tcx > ,
44
75
from : Ty < ' tcx > ,
45
76
to : Ty < ' tcx > ,
46
77
hir_id : HirId ,
47
78
) {
48
- let dl = & tcx. data_layout ;
49
- let span = tcx. hir_span ( hir_id) ;
79
+ let span = || tcx. hir_span ( hir_id) ;
50
80
let normalize = |ty| {
51
81
if let Ok ( ty) = tcx. try_normalize_erasing_regions ( typing_env, ty) {
52
82
ty
53
83
} else {
54
84
Ty :: new_error_with_message (
55
85
tcx,
56
- span,
86
+ span ( ) ,
57
87
format ! ( "tried to normalize non-wf type {ty:#?} in check_transmute" ) ,
58
88
)
59
89
}
60
90
} ;
91
+
61
92
let from = normalize ( from) ;
62
93
let to = normalize ( to) ;
63
94
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
+
70
96
// Transmutes that are only changing lifetimes are always ok.
71
97
if from == to {
72
98
return ;
73
99
}
74
100
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) ;
78
103
trace ! ( ?sk_from, ?sk_to) ;
79
104
80
105
// 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
+ {
82
109
if sk_from. same_size ( sk_to) {
83
110
return ;
84
111
}
85
112
86
113
// Special-case transmuting from `typeof(function)` and
87
114
// `Option<typeof(function)>` to present a clearer error.
88
115
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)
91
119
{
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" )
93
121
. with_note ( format ! ( "source type: {from}" ) )
94
122
. with_note ( format ! ( "target type: {to}" ) )
95
123
. with_help ( "cast with `as` to a pointer instead" )
@@ -98,35 +126,9 @@ fn check_transmute<'tcx>(
98
126
}
99
127
}
100
128
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
-
127
129
let mut err = struct_span_code_err ! (
128
130
tcx. sess. dcx( ) ,
129
- span,
131
+ span( ) ,
130
132
E0512 ,
131
133
"cannot transmute between types of different sizes, or dependently-sized types"
132
134
) ;
0 commit comments