@@ -90,9 +90,9 @@ fn layout_of<'tcx>(
9090 let cx = LayoutCx { tcx, param_env } ;
9191 let layout = layout_of_uncached ( & cx, ty) ?;
9292
93- if !naive. is_underestimate_of ( layout) {
93+ if !naive. is_compatible_with ( layout) {
9494 bug ! (
95- "the estimated naive layout is bigger than the actual layout:\n {:#?}\n {:#?}" ,
95+ "the naive layout isn't compatible with the actual layout:\n {:#?}\n {:#?}" ,
9696 naive,
9797 layout,
9898 ) ;
@@ -119,15 +119,23 @@ fn naive_layout_of_uncached<'tcx>(
119119 let tcx = cx. tcx ;
120120 let dl = cx. data_layout ( ) ;
121121
122- let scalar =
123- |value : Primitive | NaiveLayout { min_size : value. size ( dl) , min_align : value. align ( dl) . abi } ;
122+ let scalar = |value : Primitive | NaiveLayout {
123+ min_size : value. size ( dl) ,
124+ min_align : value. align ( dl) . abi ,
125+ is_exact : true ,
126+ } ;
124127
125128 let univariant = |fields : & mut dyn Iterator < Item = Ty < ' tcx > > ,
126129 repr : & ReprOptions |
127130 -> Result < NaiveLayout , & ' tcx LayoutError < ' tcx > > {
131+ if repr. pack . is_some ( ) && repr. align . is_some ( ) {
132+ cx. tcx . sess . delay_span_bug ( DUMMY_SP , "struct cannot be packed and aligned" ) ;
133+ return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
134+ }
135+
128136 // For simplicity, ignore inter-field padding; this may underestimate the size.
129137 // FIXME(reference_niches): Be smarter and implement something closer to the real layout logic.
130- let mut layout = NaiveLayout :: EMPTY ;
138+ let mut layout = NaiveLayout :: UNKNOWN ;
131139 for field in fields {
132140 let field = cx. naive_layout_of ( field) ?;
133141 layout = layout
@@ -192,20 +200,22 @@ fn naive_layout_of_uncached<'tcx>(
192200 . min_size
193201 . checked_mul ( count, cx)
194202 . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ?,
195- min_align : element . min_align ,
203+ .. * element
196204 }
197205 }
198- ty:: Slice ( element) => {
199- NaiveLayout { min_size : Size :: ZERO , min_align : cx. naive_layout_of ( element) ?. min_align }
200- }
206+ ty:: Slice ( element) => NaiveLayout {
207+ min_size : Size :: ZERO ,
208+ // NOTE: this could be unconditionally exact if `NaiveLayout` guaranteed exact align.
209+ ..* cx. naive_layout_of ( element) ?
210+ } ,
201211 ty:: Str => NaiveLayout :: EMPTY ,
202212
203213 // Odd unit types.
204214 ty:: FnDef ( ..) | ty:: Dynamic ( _, _, ty:: Dyn ) | ty:: Foreign ( ..) => NaiveLayout :: EMPTY ,
205215
206216 // FIXME(reference_niches): try to actually compute a reasonable layout estimate,
207217 // without duplicating too much code from `generator_layout`.
208- ty:: Generator ( ..) => NaiveLayout :: EMPTY ,
218+ ty:: Generator ( ..) => NaiveLayout :: UNKNOWN ,
209219
210220 ty:: Closure ( _, ref substs) => {
211221 univariant ( & mut substs. as_closure ( ) . upvar_tys ( ) , & ReprOptions :: default ( ) ) ?
@@ -223,12 +233,21 @@ fn naive_layout_of_uncached<'tcx>(
223233 }
224234
225235 ty:: Adt ( def, substs) => {
226- // For simplicity, assume that any discriminant field (if it exists)
227- // gets niched inside one of the variants; this will underestimate the size
228- // (and sometimes alignment) of enums.
229- // FIXME(reference_niches): Be smarter and actually take into accoount the discriminant.
230236 let repr = def. repr ( ) ;
231- def. variants ( ) . iter ( ) . try_fold ( NaiveLayout :: EMPTY , |layout, v| {
237+ let base = if def. is_struct ( ) && !repr. simd ( ) {
238+ // FIXME(reference_niches): compute proper alignment for SIMD types.
239+ NaiveLayout :: EMPTY
240+ } else {
241+ // For simplicity, assume that any discriminant field (if it exists)
242+ // gets niched inside one of the variants; this will underestimate the size
243+ // (and sometimes alignment) of enums.
244+ // FIXME(reference_niches): Be smarter and actually take into accoount the discriminant.
245+ // Also consider adding a special case for null-optimized enums, so that we can have
246+ // `Option<&T>: PointerLike` in generic contexts.
247+ NaiveLayout :: UNKNOWN
248+ } ;
249+
250+ def. variants ( ) . iter ( ) . try_fold ( base, |layout, v| {
232251 let mut fields = v. fields . iter ( ) . map ( |f| f. ty ( tcx, substs) ) ;
233252 let vlayout = univariant ( & mut fields, & repr) ?;
234253 Ok ( layout. union ( & vlayout) )
@@ -260,12 +279,10 @@ fn univariant_uninterned<'tcx>(
260279 kind : StructKind ,
261280) -> Result < LayoutS , & ' tcx LayoutError < ' tcx > > {
262281 let dl = cx. data_layout ( ) ;
263- let pack = repr. pack ;
264- if pack. is_some ( ) && repr. align . is_some ( ) {
265- cx. tcx . sess . delay_span_bug ( DUMMY_SP , "struct cannot be packed and aligned" ) ;
266- return Err ( cx. tcx . arena . alloc ( LayoutError :: Unknown ( ty) ) ) ;
267- }
268-
282+ assert ! (
283+ !( repr. pack. is_some( ) && repr. align. is_some( ) ) ,
284+ "already rejected by `naive_layout_of`"
285+ ) ;
269286 cx. univariant ( dl, fields, repr, kind) . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) )
270287}
271288
@@ -325,17 +342,7 @@ fn layout_of_uncached<'tcx>(
325342 if !ty. is_unsafe_ptr ( ) {
326343 // Calling `layout_of` here would cause a query cycle for recursive types;
327344 // so use a conservative estimate that doesn't look past references.
328- let naive = match cx. naive_layout_of ( pointee) {
329- Ok ( n) => n. layout ,
330- // This can happen when computing the `SizeSkeleton` of a generic type.
331- Err ( LayoutError :: Unknown ( _) ) => {
332- // TODO(reference_niches): this is *very* incorrect, but we can't
333- // return an error here; this would break transmute checks.
334- // We need some other solution.
335- NaiveLayout :: EMPTY
336- }
337- Err ( err) => return Err ( err) ,
338- } ;
345+ let naive = cx. naive_layout_of ( pointee) ?. layout ;
339346
340347 let niches = match * pointee. kind ( ) {
341348 ty:: FnDef ( def, ..)
0 commit comments