@@ -5,7 +5,8 @@ use rustc_index::{IndexSlice, IndexVec};
55use rustc_middle:: mir:: { GeneratorLayout , GeneratorSavedLocal } ;
66use rustc_middle:: query:: Providers ;
77use 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 ,
910} ;
1011use rustc_middle:: ty:: {
1112 self , AdtDef , EarlyBinder , GenericArgsRef , ReprOptions , Ty , TyCtxt , TypeVisitableExt ,
@@ -24,14 +25,14 @@ use crate::errors::{
2425use crate :: layout_sanity_check:: sanity_check_layout;
2526
2627pub fn provide ( providers : & mut Providers ) {
27- * providers = Providers { layout_of, ..* providers } ;
28+ * providers = Providers { layout_of, naive_layout_of , ..* providers } ;
2829}
2930
3031#[ instrument( skip( tcx, query) , level = "debug" ) ]
31- fn layout_of < ' tcx > (
32+ fn naive_layout_of < ' tcx > (
3233 tcx : TyCtxt < ' tcx > ,
3334 query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
34- ) -> Result < TyAndLayout < ' tcx > , & ' tcx LayoutError < ' tcx > > {
35+ ) -> Result < TyAndNaiveLayout < ' tcx > , & ' tcx LayoutError < ' tcx > > {
3536 let ( param_env, ty) = query. into_parts ( ) ;
3637 debug ! ( ?ty) ;
3738
@@ -53,16 +54,43 @@ fn layout_of<'tcx>(
5354
5455 if ty != unnormalized_ty {
5556 // 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) ) ;
5758 }
5859
5960 let cx = LayoutCx { tcx, param_env } ;
61+ let layout = naive_layout_of_uncached ( & cx, ty) ?;
62+ Ok ( TyAndNaiveLayout { ty, layout } )
63+ }
6064
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 } ;
6182 let layout = layout_of_uncached ( & cx, ty) ?;
62- let layout = TyAndLayout { ty, layout } ;
6383
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+ }
6591
92+ let layout = TyAndLayout { ty, layout } ;
93+ record_layout_for_printing ( & cx, layout) ;
6694 sanity_check_layout ( & cx, & layout) ;
6795
6896 Ok ( layout)
@@ -75,6 +103,132 @@ fn error<'tcx>(
75103 cx. tcx . arena . alloc ( err)
76104}
77105
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+
78232fn univariant_uninterned < ' tcx > (
79233 cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
80234 ty : Ty < ' tcx > ,
@@ -146,6 +300,14 @@ fn layout_of_uncached<'tcx>(
146300 ty:: Ref ( _, pointee, _) | ty:: RawPtr ( ty:: TypeAndMut { ty : pointee, .. } ) => {
147301 let mut data_ptr = scalar_unit ( Pointer ( AddressSpace :: DATA ) ) ;
148302 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+ }
149311 data_ptr. valid_range_mut ( ) . start = 1 ;
150312 }
151313
@@ -558,18 +720,15 @@ fn layout_of_uncached<'tcx>(
558720 }
559721
560722 // 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`" ) ;
573732 }
574733 } )
575734}
0 commit comments