@@ -154,9 +154,19 @@ fn naive_layout_of_uncached<'tcx>(
154154 ty:: Never => NaiveLayout :: EMPTY ,
155155
156156 // Potentially-wide pointers.
157- ty:: Ref ( _, _, _) | ty:: RawPtr ( _) => {
158- // TODO(reference_niches): handle wide pointers
159- scalar ( Pointer ( AddressSpace :: DATA ) )
157+ ty:: Ref ( _, pointee, _) | ty:: RawPtr ( ty:: TypeAndMut { ty : pointee, .. } ) => {
158+ let data_ptr = scalar ( Pointer ( AddressSpace :: DATA ) ) ;
159+
160+ if let Some ( metadata) = ptr_metadata_scalar ( cx, pointee) ? {
161+ // Effectively a (ptr, meta) tuple.
162+ data_ptr
163+ . concat ( & scalar ( metadata. primitive ( ) ) , cx)
164+ . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ?
165+ . pad_to_align ( )
166+ } else {
167+ // No metadata, this is a thin pointer.
168+ data_ptr
169+ }
160170 }
161171
162172 ty:: Dynamic ( _, _, ty:: DynStar ) => {
@@ -165,10 +175,15 @@ fn naive_layout_of_uncached<'tcx>(
165175 }
166176
167177 // Arrays and slices.
168- ty:: Array ( element, _count) => {
178+ ty:: Array ( element, count) => {
179+ let count = compute_array_count ( cx, count)
180+ . ok_or_else ( || error ( cx, LayoutError :: Unknown ( ty) ) ) ?;
169181 let element = cx. naive_layout_of ( element) ?;
170182 NaiveLayout {
171- min_size : Size :: ZERO , // TODO(reference_niches): proper array size
183+ min_size : element
184+ . min_size
185+ . checked_mul ( count, cx)
186+ . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ?,
172187 min_align : element. min_align ,
173188 }
174189 }
@@ -311,72 +326,13 @@ fn layout_of_uncached<'tcx>(
311326 data_ptr. valid_range_mut ( ) . start = 1 ;
312327 }
313328
314- let pointee = tcx. normalize_erasing_regions ( param_env, pointee) ;
315- if pointee. is_sized ( tcx, param_env) {
316- return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
317- }
318-
319- let metadata = if let Some ( metadata_def_id) = tcx. lang_items ( ) . metadata_type ( )
320- // Projection eagerly bails out when the pointee references errors,
321- // fall back to structurally deducing metadata.
322- && !pointee. references_error ( )
323- {
324- let pointee_metadata = Ty :: new_projection ( tcx, metadata_def_id, [ pointee] ) ;
325- let metadata_ty = match tcx. try_normalize_erasing_regions (
326- param_env,
327- pointee_metadata,
328- ) {
329- Ok ( metadata_ty) => metadata_ty,
330- Err ( mut err) => {
331- // Usually `<Ty as Pointee>::Metadata` can't be normalized because
332- // its struct tail cannot be normalized either, so try to get a
333- // more descriptive layout error here, which will lead to less confusing
334- // diagnostics.
335- match tcx. try_normalize_erasing_regions (
336- param_env,
337- tcx. struct_tail_without_normalization ( pointee) ,
338- ) {
339- Ok ( _) => { } ,
340- Err ( better_err) => {
341- err = better_err;
342- }
343- }
344- return Err ( error ( cx, LayoutError :: NormalizationFailure ( pointee, err) ) ) ;
345- } ,
346- } ;
347-
348- let metadata_layout = cx. layout_of ( metadata_ty) ?;
349- // If the metadata is a 1-zst, then the pointer is thin.
350- if metadata_layout. is_zst ( ) && metadata_layout. align . abi . bytes ( ) == 1 {
351- return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
352- }
353-
354- let Abi :: Scalar ( metadata) = metadata_layout. abi else {
355- return Err ( error ( cx, LayoutError :: Unknown ( pointee) ) ) ;
356- } ;
357-
358- metadata
329+ if let Some ( metadata) = ptr_metadata_scalar ( cx, pointee) ? {
330+ // Effectively a (ptr, meta) tuple.
331+ tcx. mk_layout ( cx. scalar_pair ( data_ptr, metadata) )
359332 } else {
360- let unsized_part = tcx. struct_tail_erasing_lifetimes ( pointee, param_env) ;
361-
362- match unsized_part. kind ( ) {
363- ty:: Foreign ( ..) => {
364- return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
365- }
366- ty:: Slice ( _) | ty:: Str => scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ,
367- ty:: Dynamic ( ..) => {
368- let mut vtable = scalar_unit ( Pointer ( AddressSpace :: DATA ) ) ;
369- vtable. valid_range_mut ( ) . start = 1 ;
370- vtable
371- }
372- _ => {
373- return Err ( error ( cx, LayoutError :: Unknown ( pointee) ) ) ;
374- }
375- }
376- } ;
377-
378- // Effectively a (ptr, meta) tuple.
379- tcx. mk_layout ( cx. scalar_pair ( data_ptr, metadata) )
333+ // No metadata, this is a thin pointer.
334+ tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) )
335+ }
380336 }
381337
382338 ty:: Dynamic ( _, _, ty:: DynStar ) => {
@@ -388,16 +344,8 @@ fn layout_of_uncached<'tcx>(
388344 }
389345
390346 // Arrays and slices.
391- ty:: Array ( element, mut count) => {
392- if count. has_projections ( ) {
393- count = tcx. normalize_erasing_regions ( param_env, count) ;
394- if count. has_projections ( ) {
395- return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
396- }
397- }
398-
399- let count = count
400- . try_eval_target_usize ( tcx, param_env)
347+ ty:: Array ( element, count) => {
348+ let count = compute_array_count ( cx, count)
401349 . ok_or_else ( || error ( cx, LayoutError :: Unknown ( ty) ) ) ?;
402350 let element = cx. layout_of ( element) ?;
403351 let size = element
@@ -733,6 +681,93 @@ fn layout_of_uncached<'tcx>(
733681 } )
734682}
735683
684+ fn compute_array_count < ' tcx > (
685+ cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
686+ mut count : ty:: Const < ' tcx > ,
687+ ) -> Option < u64 > {
688+ let LayoutCx { tcx, param_env } = * cx;
689+ if count. has_projections ( ) {
690+ count = tcx. normalize_erasing_regions ( param_env, count) ;
691+ if count. has_projections ( ) {
692+ return None ;
693+ }
694+ }
695+
696+ count. try_eval_target_usize ( tcx, param_env)
697+ }
698+
699+ fn ptr_metadata_scalar < ' tcx > (
700+ cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
701+ pointee : Ty < ' tcx > ,
702+ ) -> Result < Option < Scalar > , & ' tcx LayoutError < ' tcx > > {
703+ let dl = cx. data_layout ( ) ;
704+ let scalar_unit = |value : Primitive | {
705+ let size = value. size ( dl) ;
706+ assert ! ( size. bits( ) <= 128 ) ;
707+ Scalar :: Initialized { value, valid_range : WrappingRange :: full ( size) }
708+ } ;
709+
710+ let LayoutCx { tcx, param_env } = * cx;
711+
712+ let pointee = tcx. normalize_erasing_regions ( param_env, pointee) ;
713+ if pointee. is_sized ( tcx, param_env) {
714+ return Ok ( None ) ;
715+ }
716+
717+ if let Some ( metadata_def_id) = tcx. lang_items ( ) . metadata_type ( )
718+ // Projection eagerly bails out when the pointee references errors,
719+ // fall back to structurally deducing metadata.
720+ && !pointee. references_error ( )
721+ {
722+ let pointee_metadata = Ty :: new_projection ( tcx, metadata_def_id, [ pointee] ) ;
723+ let metadata_ty = match tcx. try_normalize_erasing_regions (
724+ param_env,
725+ pointee_metadata,
726+ ) {
727+ Ok ( metadata_ty) => metadata_ty,
728+ Err ( mut err) => {
729+ // Usually `<Ty as Pointee>::Metadata` can't be normalized because
730+ // its struct tail cannot be normalized either, so try to get a
731+ // more descriptive layout error here, which will lead to less confusing
732+ // diagnostics.
733+ match tcx. try_normalize_erasing_regions (
734+ param_env,
735+ tcx. struct_tail_without_normalization ( pointee) ,
736+ ) {
737+ Ok ( _) => { } ,
738+ Err ( better_err) => {
739+ err = better_err;
740+ }
741+ }
742+ return Err ( error ( cx, LayoutError :: NormalizationFailure ( pointee, err) ) ) ;
743+ } ,
744+ } ;
745+
746+ let metadata_layout = cx. layout_of ( metadata_ty) ?;
747+
748+ if metadata_layout. is_zst ( ) && metadata_layout. align . abi . bytes ( ) == 1 {
749+ Ok ( None ) // If the metadata is a 1-zst, then the pointer is thin.
750+ } else if let Abi :: Scalar ( metadata) = metadata_layout. abi {
751+ Ok ( Some ( metadata) )
752+ } else {
753+ Err ( error ( cx, LayoutError :: Unknown ( pointee) ) )
754+ }
755+ } else {
756+ let unsized_part = tcx. struct_tail_erasing_lifetimes ( pointee, param_env) ;
757+
758+ match unsized_part. kind ( ) {
759+ ty:: Foreign ( ..) => Ok ( None ) ,
760+ ty:: Slice ( _) | ty:: Str => Ok ( Some ( scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ) ) ,
761+ ty:: Dynamic ( ..) => {
762+ let mut vtable = scalar_unit ( Pointer ( AddressSpace :: DATA ) ) ;
763+ vtable. valid_range_mut ( ) . start = 1 ;
764+ Ok ( Some ( vtable) )
765+ }
766+ _ => Err ( error ( cx, LayoutError :: Unknown ( pointee) ) ) ,
767+ }
768+ }
769+ }
770+
736771/// Overlap eligibility and variant assignment for each GeneratorSavedLocal.
737772#[ derive( Clone , Debug , PartialEq ) ]
738773enum SavedLocalEligibility {
0 commit comments