@@ -5,7 +5,8 @@ use rustc_index::{IndexSlice, IndexVec};
5
5
use rustc_middle:: mir:: { GeneratorLayout , GeneratorSavedLocal } ;
6
6
use rustc_middle:: query:: Providers ;
7
7
use rustc_middle:: ty:: layout:: {
8
- IntegerExt , LayoutCx , LayoutError , LayoutOf , TyAndLayout , MAX_SIMD_LANES ,
8
+ IntegerExt , LayoutCx , LayoutError , LayoutOf , NaiveLayout , TyAndLayout , TyAndNaiveLayout ,
9
+ MAX_SIMD_LANES ,
9
10
} ;
10
11
use rustc_middle:: ty:: {
11
12
self , AdtDef , EarlyBinder , GenericArgsRef , ReprOptions , Ty , TyCtxt , TypeVisitableExt ,
@@ -24,14 +25,14 @@ use crate::errors::{
24
25
use crate :: layout_sanity_check:: sanity_check_layout;
25
26
26
27
pub fn provide ( providers : & mut Providers ) {
27
- * providers = Providers { layout_of, ..* providers } ;
28
+ * providers = Providers { layout_of, naive_layout_of , ..* providers } ;
28
29
}
29
30
30
31
#[ instrument( skip( tcx, query) , level = "debug" ) ]
31
- fn layout_of < ' tcx > (
32
+ fn naive_layout_of < ' tcx > (
32
33
tcx : TyCtxt < ' tcx > ,
33
34
query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
34
- ) -> Result < TyAndLayout < ' tcx > , & ' tcx LayoutError < ' tcx > > {
35
+ ) -> Result < TyAndNaiveLayout < ' tcx > , & ' tcx LayoutError < ' tcx > > {
35
36
let ( param_env, ty) = query. into_parts ( ) ;
36
37
debug ! ( ?ty) ;
37
38
@@ -53,16 +54,43 @@ fn layout_of<'tcx>(
53
54
54
55
if ty != unnormalized_ty {
55
56
// Ensure this layout is also cached for the normalized type.
56
- return tcx. layout_of ( param_env. and ( ty) ) ;
57
+ return tcx. naive_layout_of ( param_env. and ( ty) ) ;
57
58
}
58
59
59
60
let cx = LayoutCx { tcx, param_env } ;
61
+ let layout = naive_layout_of_uncached ( & cx, ty) ?;
62
+ Ok ( TyAndNaiveLayout { ty, layout } )
63
+ }
60
64
65
+ #[ instrument( skip( tcx, query) , level = "debug" ) ]
66
+ fn layout_of < ' tcx > (
67
+ tcx : TyCtxt < ' tcx > ,
68
+ query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
69
+ ) -> Result < TyAndLayout < ' tcx > , & ' tcx LayoutError < ' tcx > > {
70
+ let ( param_env, unnormalized_ty) = query. into_parts ( ) ;
71
+ let param_env = param_env. with_reveal_all_normalized ( tcx) ;
72
+ // `naive_layout_of` takes care of normalizing the type.
73
+ let naive = tcx. naive_layout_of ( query) ?;
74
+ let ty = naive. ty ;
75
+
76
+ if ty != unnormalized_ty {
77
+ // Ensure this layout is also cached for the normalized type.
78
+ return tcx. layout_of ( param_env. and ( ty) ) ;
79
+ }
80
+
81
+ let cx = LayoutCx { tcx, param_env } ;
61
82
let layout = layout_of_uncached ( & cx, ty) ?;
62
- let layout = TyAndLayout { ty, layout } ;
63
83
64
- record_layout_for_printing ( & cx, layout) ;
84
+ if !naive. is_underestimate_of ( layout) {
85
+ bug ! (
86
+ "the estimated naive layout is bigger than the actual layout:\n {:#?}\n {:#?}" ,
87
+ naive,
88
+ layout,
89
+ ) ;
90
+ }
65
91
92
+ let layout = TyAndLayout { ty, layout } ;
93
+ record_layout_for_printing ( & cx, layout) ;
66
94
sanity_check_layout ( & cx, & layout) ;
67
95
68
96
Ok ( layout)
@@ -75,6 +103,132 @@ fn error<'tcx>(
75
103
cx. tcx . arena . alloc ( err)
76
104
}
77
105
106
+ fn naive_layout_of_uncached < ' tcx > (
107
+ cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
108
+ ty : Ty < ' tcx > ,
109
+ ) -> Result < NaiveLayout , & ' tcx LayoutError < ' tcx > > {
110
+ let tcx = cx. tcx ;
111
+ let dl = cx. data_layout ( ) ;
112
+
113
+ let scalar =
114
+ |value : Primitive | NaiveLayout { min_size : value. size ( dl) , min_align : value. align ( dl) . abi } ;
115
+
116
+ let univariant = |fields : & mut dyn Iterator < Item = Ty < ' tcx > > ,
117
+ repr : & ReprOptions |
118
+ -> Result < NaiveLayout , & ' tcx LayoutError < ' tcx > > {
119
+ // For simplicity, ignore inter-field padding; this may underestimate the size.
120
+ // FIXME(reference_niches): Be smarter and implement something closer to the real layout logic.
121
+ let mut layout = NaiveLayout :: EMPTY ;
122
+ for field in fields {
123
+ let field = cx. naive_layout_of ( field) ?;
124
+ layout = layout
125
+ . concat ( & field, cx)
126
+ . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ?;
127
+ }
128
+
129
+ if let Some ( align) = repr. align {
130
+ layout. min_align = std:: cmp:: max ( layout. min_align , align) ;
131
+ }
132
+ if let Some ( pack) = repr. pack {
133
+ layout. min_align = std:: cmp:: min ( layout. min_align , pack) ;
134
+ }
135
+
136
+ Ok ( layout. pad_to_align ( ) )
137
+ } ;
138
+
139
+ debug_assert ! ( !ty. has_non_region_infer( ) ) ;
140
+
141
+ Ok ( match * ty. kind ( ) {
142
+ // Basic scalars
143
+ ty:: Bool => scalar ( Int ( I8 , false ) ) ,
144
+ ty:: Char => scalar ( Int ( I32 , false ) ) ,
145
+ ty:: Int ( ity) => scalar ( Int ( Integer :: from_int_ty ( dl, ity) , true ) ) ,
146
+ ty:: Uint ( ity) => scalar ( Int ( Integer :: from_uint_ty ( dl, ity) , false ) ) ,
147
+ ty:: Float ( fty) => scalar ( match fty {
148
+ ty:: FloatTy :: F32 => F32 ,
149
+ ty:: FloatTy :: F64 => F64 ,
150
+ } ) ,
151
+ ty:: FnPtr ( _) => scalar ( Pointer ( dl. instruction_address_space ) ) ,
152
+
153
+ // The never type.
154
+ ty:: Never => NaiveLayout :: EMPTY ,
155
+
156
+ // Potentially-wide pointers.
157
+ ty:: Ref ( _, _, _) | ty:: RawPtr ( _) => {
158
+ // TODO(reference_niches): handle wide pointers
159
+ scalar ( Pointer ( AddressSpace :: DATA ) )
160
+ }
161
+
162
+ ty:: Dynamic ( _, _, ty:: DynStar ) => {
163
+ let ptr = scalar ( Pointer ( AddressSpace :: DATA ) ) ;
164
+ ptr. concat ( & ptr, cx) . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ?
165
+ }
166
+
167
+ // Arrays and slices.
168
+ ty:: Array ( element, _count) => {
169
+ let element = cx. naive_layout_of ( element) ?;
170
+ NaiveLayout {
171
+ min_size : Size :: ZERO , // TODO(reference_niches): proper array size
172
+ min_align : element. min_align ,
173
+ }
174
+ }
175
+ ty:: Slice ( element) => {
176
+ NaiveLayout { min_size : Size :: ZERO , min_align : cx. naive_layout_of ( element) ?. min_align }
177
+ }
178
+ ty:: Str => NaiveLayout :: EMPTY ,
179
+
180
+ // Odd unit types.
181
+ ty:: FnDef ( ..) | ty:: Dynamic ( _, _, ty:: Dyn ) | ty:: Foreign ( ..) => NaiveLayout :: EMPTY ,
182
+
183
+ // FIXME(reference_niches): try to actually compute a reasonable layout estimate,
184
+ // without duplicating too much code from `generator_layout`.
185
+ ty:: Generator ( ..) => NaiveLayout :: EMPTY ,
186
+
187
+ ty:: Closure ( _, ref substs) => {
188
+ univariant ( & mut substs. as_closure ( ) . upvar_tys ( ) , & ReprOptions :: default ( ) ) ?
189
+ }
190
+
191
+ ty:: Tuple ( tys) => univariant ( & mut tys. iter ( ) , & ReprOptions :: default ( ) ) ?,
192
+
193
+ ty:: Adt ( def, substs) if def. is_union ( ) => {
194
+ let repr = def. repr ( ) ;
195
+ let only_variant = & def. variants ( ) [ FIRST_VARIANT ] ;
196
+ only_variant. fields . iter ( ) . try_fold ( NaiveLayout :: EMPTY , |layout, f| {
197
+ let mut fields = std:: iter:: once ( f. ty ( tcx, substs) ) ;
198
+ univariant ( & mut fields, & repr) . map ( |l| layout. union ( & l) )
199
+ } ) ?
200
+ }
201
+
202
+ ty:: Adt ( def, substs) => {
203
+ // For simplicity, assume that any discriminant field (if it exists)
204
+ // gets niched inside one of the variants; this will underestimate the size
205
+ // (and sometimes alignment) of enums.
206
+ // FIXME(reference_niches): Be smarter and actually take into accoount the discriminant.
207
+ let repr = def. repr ( ) ;
208
+ def. variants ( ) . iter ( ) . try_fold ( NaiveLayout :: EMPTY , |layout, v| {
209
+ let mut fields = v. fields . iter ( ) . map ( |f| f. ty ( tcx, substs) ) ;
210
+ let vlayout = univariant ( & mut fields, & repr) ?;
211
+ Ok ( layout. union ( & vlayout) )
212
+ } ) ?
213
+ }
214
+
215
+ // Types with no meaningful known layout.
216
+ ty:: Alias ( ..) => {
217
+ // NOTE(eddyb) `layout_of` query should've normalized these away,
218
+ // if that was possible, so there's no reason to try again here.
219
+ return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
220
+ }
221
+
222
+ ty:: Bound ( ..) | ty:: GeneratorWitness ( ..) | ty:: GeneratorWitnessMIR ( ..) | ty:: Infer ( _) => {
223
+ bug ! ( "Layout::compute: unexpected type `{}`" , ty)
224
+ }
225
+
226
+ ty:: Placeholder ( ..) | ty:: Param ( _) | ty:: Error ( _) => {
227
+ return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
228
+ }
229
+ } )
230
+ }
231
+
78
232
fn univariant_uninterned < ' tcx > (
79
233
cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
80
234
ty : Ty < ' tcx > ,
@@ -146,6 +300,14 @@ fn layout_of_uncached<'tcx>(
146
300
ty:: Ref ( _, pointee, _) | ty:: RawPtr ( ty:: TypeAndMut { ty : pointee, .. } ) => {
147
301
let mut data_ptr = scalar_unit ( Pointer ( AddressSpace :: DATA ) ) ;
148
302
if !ty. is_unsafe_ptr ( ) {
303
+ match cx. naive_layout_of ( pointee) {
304
+ // TODO(reference_niches): actually use the naive layout to set
305
+ // reference niches; the query is still kept to for testing purposes.
306
+ Ok ( _) => ( ) ,
307
+ // This can happen when computing the `SizeSkeleton` of a generic type.
308
+ Err ( LayoutError :: Unknown ( _) ) => ( ) ,
309
+ Err ( err) => return Err ( err) ,
310
+ }
149
311
data_ptr. valid_range_mut ( ) . start = 1 ;
150
312
}
151
313
@@ -558,18 +720,15 @@ fn layout_of_uncached<'tcx>(
558
720
}
559
721
560
722
// Types with no meaningful known layout.
561
- ty:: Alias ( ..) => {
562
- // NOTE(eddyb) `layout_of` query should've normalized these away,
563
- // if that was possible, so there's no reason to try again here.
564
- return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
565
- }
566
-
567
- ty:: Bound ( ..) | ty:: GeneratorWitness ( ..) | ty:: GeneratorWitnessMIR ( ..) | ty:: Infer ( _) => {
568
- bug ! ( "Layout::compute: unexpected type `{}`" , ty)
569
- }
570
-
571
- ty:: Placeholder ( ..) | ty:: Param ( _) | ty:: Error ( _) => {
572
- return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
723
+ ty:: Alias ( ..)
724
+ | ty:: Bound ( ..)
725
+ | ty:: GeneratorWitness ( ..)
726
+ | ty:: GeneratorWitnessMIR ( ..)
727
+ | ty:: Infer ( _)
728
+ | ty:: Placeholder ( ..)
729
+ | ty:: Param ( _)
730
+ | ty:: Error ( _) => {
731
+ unreachable ! ( "already rejected by `naive_layout_of`" ) ;
573
732
}
574
733
} )
575
734
}
0 commit comments