11use std:: fmt:: Debug ;
2- use std:: iter;
2+ use std:: ops:: ControlFlow ;
3+ use std:: { cmp, iter} ;
34
45use hir:: def_id:: DefId ;
56use rustc_hir as hir;
@@ -13,12 +14,14 @@ use rustc_middle::ty::layout::{
1314} ;
1415use rustc_middle:: ty:: print:: with_no_trimmed_paths;
1516use rustc_middle:: ty:: {
16- self , AdtDef , CoroutineArgsExt , EarlyBinder , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt ,
17+ self , AdtDef , CoroutineArgsExt , EarlyBinder , GenericArgsRef , ParamEnv , Ty , TyCtxt ,
18+ TypeVisitableExt ,
1719} ;
1820use rustc_session:: { DataTypeKind , FieldInfo , FieldKind , SizeKind , VariantInfo } ;
1921use rustc_span:: sym;
2022use rustc_span:: symbol:: Symbol ;
2123use rustc_target:: abi:: * ;
24+ use rustc_type_ir:: DynKind ;
2225use tracing:: { debug, instrument, trace} ;
2326
2427use crate :: errors:: {
@@ -155,7 +158,7 @@ fn layout_of_uncached<'tcx>(
155158 } ;
156159 debug_assert ! ( !ty. has_non_region_infer( ) ) ;
157160
158- Ok ( match * ty. kind ( ) {
161+ let layout = match * ty. kind ( ) {
159162 ty:: Pat ( ty, pat) => {
160163 let layout = cx. layout_of ( ty) ?. layout ;
161164 let mut layout = LayoutS :: clone ( & layout. 0 ) ;
@@ -192,7 +195,6 @@ fn layout_of_uncached<'tcx>(
192195 }
193196 }
194197 }
195-
196198 // Basic scalars.
197199 ty:: Bool => tcx. mk_layout ( LayoutS :: scalar ( cx, Scalar :: Initialized {
198200 value : Int ( I8 , false ) ,
@@ -263,10 +265,32 @@ fn layout_of_uncached<'tcx>(
263265 return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
264266 }
265267
266- let Abi :: Scalar ( metadata) = metadata_layout. abi else {
268+ let Abi :: Scalar ( mut metadata) = metadata_layout. abi else {
267269 return Err ( error ( cx, LayoutError :: Unknown ( pointee) ) ) ;
268270 } ;
269271
272+ if !ty. is_unsafe_ptr ( ) && metadata_ty == tcx. types . usize {
273+ let tail = tcx. struct_tail_for_codegen ( pointee, param_env) ;
274+ // // eprintln!("usize-meta {:?} {}", pointee, pointee_zst);
275+ match tail. kind ( ) {
276+ ty:: Slice ( element) => match ty_is_non_zst ( * element, param_env, tcx) {
277+ NonZst :: True => {
278+ metadata. valid_range_mut ( ) . end =
279+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128
280+ }
281+ NonZst :: Unknown => return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ,
282+ _ => { }
283+ } ,
284+ ty:: Str => {
285+ metadata. valid_range_mut ( ) . end =
286+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128 ;
287+ }
288+ _ => {
289+ eprint ! ( "unexpected tail {:?}" , tail) ;
290+ }
291+ }
292+ }
293+
270294 metadata
271295 } else {
272296 let unsized_part = tcx. struct_tail_for_codegen ( pointee, param_env) ;
@@ -275,7 +299,28 @@ fn layout_of_uncached<'tcx>(
275299 ty:: Foreign ( ..) => {
276300 return Ok ( tcx. mk_layout ( LayoutS :: scalar ( cx, data_ptr) ) ) ;
277301 }
278- ty:: Slice ( _) | ty:: Str => scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ,
302+ ty:: Slice ( element) => {
303+ let mut metadata = scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ;
304+ if !ty. is_unsafe_ptr ( ) {
305+ match ty_is_non_zst ( * element, param_env, tcx) {
306+ NonZst :: True => {
307+ metadata. valid_range_mut ( ) . end =
308+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128
309+ }
310+ NonZst :: Unknown => return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ,
311+ _ => { }
312+ }
313+ }
314+ metadata
315+ }
316+ ty:: Str => {
317+ let mut metadata = scalar_unit ( Int ( dl. ptr_sized_integer ( ) , false ) ) ;
318+ if !ty. is_unsafe_ptr ( ) {
319+ metadata. valid_range_mut ( ) . end =
320+ dl. ptr_sized_integer ( ) . signed_max ( ) as u128 ;
321+ }
322+ metadata
323+ }
279324 ty:: Dynamic ( ..) => {
280325 let mut vtable = scalar_unit ( Pointer ( AddressSpace :: DATA ) ) ;
281326 vtable. valid_range_mut ( ) . start = 1 ;
@@ -667,7 +712,157 @@ fn layout_of_uncached<'tcx>(
667712 ty:: Placeholder ( ..) | ty:: Param ( _) => {
668713 return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
669714 }
670- } )
715+ } ;
716+
717+ #[ cfg( debug_assertions) ]
718+ if layout. is_sized ( ) && !layout. abi . is_uninhabited ( ) {
719+ match ( ty_is_non_zst ( ty, param_env, tcx) , layout. is_zst ( ) ) {
720+ ( NonZst :: Unknown , _) => {
721+ bug ! ( "ZSTness should not be unknown at this point {:?} {:?}" , ty, layout)
722+ }
723+ ( n @ ( NonZst :: False | NonZst :: Uninhabited ) , false ) => {
724+ bug ! ( "{:?} is not a ZST but ty_is_non_zst() thinks it is NonZst::{:?}" , ty, n)
725+ }
726+ ( NonZst :: True , true ) => bug ! ( "{:?} is a ZST but ty_is_non_zst() thinks it isn't" , ty) ,
727+ _ => { }
728+ }
729+ }
730+
731+ Ok ( layout)
732+ }
733+
734+ fn ty_is_non_zst < ' tcx > ( ty : Ty < ' tcx > , param_env : ParamEnv < ' tcx > , tcx : TyCtxt < ' tcx > ) -> NonZst {
735+ fn fold_fields < ' tcx > (
736+ mut it : impl Iterator < Item = Ty < ' tcx > > ,
737+ param_env : ParamEnv < ' tcx > ,
738+ tcx : TyCtxt < ' tcx > ,
739+ ) -> NonZst {
740+ let ( ControlFlow :: Break ( res) | ControlFlow :: Continue ( res) ) =
741+ it. try_fold ( NonZst :: False , |acc, ty| {
742+ if acc == NonZst :: True {
743+ return ControlFlow :: Break ( acc) ;
744+ }
745+
746+ ControlFlow :: Continue ( cmp:: max ( acc, ty_is_non_zst ( ty, param_env, tcx) ) )
747+ } ) ;
748+
749+ res
750+ }
751+
752+ match ty. kind ( ) {
753+ ty:: Infer ( ty:: IntVar ( _) | ty:: FloatVar ( _) )
754+ | ty:: Uint ( _)
755+ | ty:: Int ( _)
756+ | ty:: Bool
757+ | ty:: Float ( _)
758+ | ty:: FnPtr ( _, _)
759+ | ty:: RawPtr ( ..)
760+ | ty:: Dynamic ( _, _, DynKind :: DynStar )
761+ | ty:: Char
762+ | ty:: Ref ( ..) => NonZst :: True ,
763+
764+ ty:: Pat ( ty, _) => ty_is_non_zst ( * ty, param_env, tcx) ,
765+ ty:: Closure ( _, args) => fold_fields ( args. as_closure ( ) . upvar_tys ( ) . iter ( ) , param_env, tcx) ,
766+ ty:: Coroutine ( _, _) => NonZst :: True ,
767+ ty:: CoroutineClosure ( _, args) => {
768+ fold_fields ( args. as_coroutine_closure ( ) . upvar_tys ( ) . iter ( ) , param_env, tcx)
769+ }
770+ ty:: Array ( ty, len) => {
771+ let len = if len. has_aliases ( ) {
772+ tcx. normalize_erasing_regions ( param_env, * len)
773+ } else {
774+ * len
775+ } ;
776+
777+ if let Some ( len) = len. try_to_target_usize ( tcx) {
778+ if len == 0 {
779+ return NonZst :: False ;
780+ }
781+ let element_zst = ty_is_non_zst ( * ty, param_env, tcx) ;
782+ if element_zst != NonZst :: Unknown {
783+ return element_zst;
784+ }
785+ }
786+ NonZst :: Unknown
787+ }
788+ ty:: Tuple ( tys) => fold_fields ( tys. iter ( ) , param_env, tcx) ,
789+ ty:: Adt ( def, args) => {
790+ if ty. is_enum ( ) {
791+ // repr(C) enums can never be ZSTs or uninhabited.
792+ // They must have at least one variant and even if the variant has a payload that is uninhabited,
793+ // the tag is still there.
794+ if def. repr ( ) . c ( ) {
795+ return NonZst :: True ;
796+ }
797+
798+ if def. variants ( ) . len ( ) == 0 {
799+ return NonZst :: Uninhabited ;
800+ }
801+ // An enum is !ZST if
802+ // * it has a repr(int) and at least one non-uninhabited variant
803+ // * it has at least one variant with a !ZST payload
804+ // * it has multiple variants that are not uninhabited
805+
806+ let min_empty_variants = if def. repr ( ) . inhibit_enum_layout_opt ( ) { 1 } else { 2 } ;
807+
808+ // first check without recursing
809+ let simple_variants = def. variants ( ) . iter ( ) . filter ( |v| v. fields . len ( ) == 0 ) . count ( ) ;
810+ if simple_variants >= min_empty_variants {
811+ return NonZst :: True ;
812+ }
813+
814+ let mut inhabited_zst_variants = 0 ;
815+ let mut unknown = false ;
816+
817+ for variant in def. variants ( ) . iter ( ) . filter ( |v| v. fields . len ( ) != 0 ) {
818+ let variant_sized =
819+ fold_fields ( variant. fields . iter ( ) . map ( |f| f. ty ( tcx, args) ) , param_env, tcx) ;
820+
821+ match variant_sized {
822+ // enum E { A(!, u32) } counts as !ZST for our purposes
823+ NonZst :: True => return NonZst :: True ,
824+ NonZst :: False => inhabited_zst_variants += 1 ,
825+ NonZst :: Unknown => unknown = true ,
826+ NonZst :: Uninhabited => { }
827+ }
828+ }
829+
830+ if simple_variants + inhabited_zst_variants >= min_empty_variants {
831+ return NonZst :: True ;
832+ }
833+ if unknown {
834+ return NonZst :: Unknown ;
835+ }
836+ if simple_variants + inhabited_zst_variants == 0 {
837+ return NonZst :: Uninhabited ;
838+ }
839+
840+ NonZst :: False
841+ } else {
842+ fold_fields ( def. all_fields ( ) . map ( |f| f. ty ( tcx, args) ) , param_env, tcx)
843+ }
844+ }
845+ ty:: FnDef ( ..) => NonZst :: False ,
846+ ty:: Never => NonZst :: Uninhabited ,
847+ ty:: Param ( ..) => NonZst :: Unknown ,
848+ ty:: Str => NonZst :: True ,
849+ // treat unsized types as potentially-ZST
850+ ty:: Dynamic ( ..) | ty:: Slice ( ..) => NonZst :: False ,
851+ ty:: Alias ( ..) => match tcx. try_normalize_erasing_regions ( param_env, ty) {
852+ Ok ( ty) if !matches ! ( ty. kind( ) , ty:: Alias ( ..) ) => ty_is_non_zst ( ty, param_env, tcx) ,
853+ _ => NonZst :: Unknown ,
854+ } ,
855+ ty:: Error ( _) => NonZst :: Unknown ,
856+ _ => bug ! ( "is_non_zst not implemented for this kind {:?}" , ty) ,
857+ }
858+ }
859+
860+ #[ derive( Clone , Copy , PartialEq , Eq , Debug , PartialOrd , Ord ) ]
861+ enum NonZst {
862+ False ,
863+ Uninhabited ,
864+ Unknown ,
865+ True ,
671866}
672867
673868/// Overlap eligibility and variant assignment for each CoroutineSavedLocal.
0 commit comments