5
5
use core:: ops:: ControlFlow ;
6
6
use itertools:: Itertools ;
7
7
use rustc_ast:: ast:: Mutability ;
8
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
8
+ use rustc_data_structures:: fx:: FxHashSet ;
9
9
use rustc_hir as hir;
10
10
use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
11
11
use rustc_hir:: def_id:: DefId ;
@@ -16,7 +16,7 @@ use rustc_lint::LateContext;
16
16
use rustc_middle:: mir:: interpret:: Scalar ;
17
17
use rustc_middle:: mir:: ConstValue ;
18
18
use rustc_middle:: traits:: EvaluationResult ;
19
- use rustc_middle:: ty:: layout:: ValidityRequirement ;
19
+ use rustc_middle:: ty:: layout:: { LayoutOf , ValidityRequirement } ;
20
20
use rustc_middle:: ty:: {
21
21
self , AdtDef , AliasTy , AssocKind , Binder , BoundRegion , FnSig , GenericArg , GenericArgKind , GenericArgsRef ,
22
22
GenericParamDefKind , IntTy , List , ParamEnv , Region , RegionKind , ToPredicate , TraitRef , Ty , TyCtxt ,
@@ -361,50 +361,6 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
361
361
}
362
362
}
363
363
364
- // FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
365
- // this function can be removed once the `normalize` method does not panic when normalization does
366
- // not succeed
367
- /// Checks if `Ty` is normalizable. This function is useful
368
- /// to avoid crashes on `layout_of`.
369
- pub fn is_normalizable < ' tcx > ( cx : & LateContext < ' tcx > , param_env : ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> bool {
370
- is_normalizable_helper ( cx, param_env, ty, & mut FxHashMap :: default ( ) )
371
- }
372
-
373
- fn is_normalizable_helper < ' tcx > (
374
- cx : & LateContext < ' tcx > ,
375
- param_env : ParamEnv < ' tcx > ,
376
- ty : Ty < ' tcx > ,
377
- cache : & mut FxHashMap < Ty < ' tcx > , bool > ,
378
- ) -> bool {
379
- if let Some ( & cached_result) = cache. get ( & ty) {
380
- return cached_result;
381
- }
382
- // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
383
- cache. insert ( ty, false ) ;
384
- let infcx = cx. tcx . infer_ctxt ( ) . build ( ) ;
385
- let cause = ObligationCause :: dummy ( ) ;
386
- let result = if infcx. at ( & cause, param_env) . query_normalize ( ty) . is_ok ( ) {
387
- match ty. kind ( ) {
388
- ty:: Adt ( def, args) => def. variants ( ) . iter ( ) . all ( |variant| {
389
- variant
390
- . fields
391
- . iter ( )
392
- . all ( |field| is_normalizable_helper ( cx, param_env, field. ty ( cx. tcx , args) , cache) )
393
- } ) ,
394
- _ => ty. walk ( ) . all ( |generic_arg| match generic_arg. unpack ( ) {
395
- GenericArgKind :: Type ( inner_ty) if inner_ty != ty => {
396
- is_normalizable_helper ( cx, param_env, inner_ty, cache)
397
- } ,
398
- _ => true , // if inner_ty == ty, we've already checked it
399
- } ) ,
400
- }
401
- } else {
402
- false
403
- } ;
404
- cache. insert ( ty, result) ;
405
- result
406
- }
407
-
408
364
/// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any
409
365
/// integer or floating-point number type). For checking aggregation of primitive types (e.g.
410
366
/// tuples and slices of primitive type) see `is_recursively_primitive_type`
@@ -1013,10 +969,6 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
1013
969
/// Comes up with an "at least" guesstimate for the type's size, not taking into
1014
970
/// account the layout of type parameters.
1015
971
pub fn approx_ty_size < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> u64 {
1016
- use rustc_middle:: ty:: layout:: LayoutOf ;
1017
- if !is_normalizable ( cx, cx. param_env , ty) {
1018
- return 0 ;
1019
- }
1020
972
match ( cx. layout_of ( ty) . map ( |layout| layout. size . bytes ( ) ) , ty. kind ( ) ) {
1021
973
( Ok ( size) , _) => size,
1022
974
( Err ( _) , ty:: Tuple ( list) ) => list. iter ( ) . map ( |t| approx_ty_size ( cx, t) ) . sum ( ) ,
@@ -1290,3 +1242,113 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>
1290
1242
pub fn is_manually_drop ( ty : Ty < ' _ > ) -> bool {
1291
1243
ty. ty_adt_def ( ) . map_or ( false , AdtDef :: is_manually_drop)
1292
1244
}
1245
+
1246
+ #[ derive( Clone , Copy ) ]
1247
+ pub enum Sizedness {
1248
+ /// The type is uninhabited. (e.g. `!`)
1249
+ Uninhabited ,
1250
+ /// The type is zero-sized.
1251
+ Zero ,
1252
+ /// The type has some other size or an unknown size.
1253
+ Other ,
1254
+ }
1255
+ impl Sizedness {
1256
+ pub fn is_zero ( self ) -> bool {
1257
+ matches ! ( self , Self :: Zero )
1258
+ }
1259
+
1260
+ pub fn is_uninhabited ( self ) -> bool {
1261
+ matches ! ( self , Self :: Uninhabited )
1262
+ }
1263
+ }
1264
+
1265
+ /// Calculates the sizedness of a type.
1266
+ pub fn sizedness_of < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> Sizedness {
1267
+ fn for_list < ' tcx > (
1268
+ tcx : TyCtxt < ' tcx > ,
1269
+ param_env : ParamEnv < ' tcx > ,
1270
+ tys : impl IntoIterator < Item = Ty < ' tcx > > ,
1271
+ ) -> Sizedness {
1272
+ let mut res = Sizedness :: Zero ;
1273
+ for ty in tys {
1274
+ match sizedness_of ( tcx, param_env, ty) {
1275
+ Sizedness :: Uninhabited => return Sizedness :: Uninhabited ,
1276
+ Sizedness :: Other => res = Sizedness :: Other ,
1277
+ Sizedness :: Zero => { } ,
1278
+ }
1279
+ }
1280
+ res
1281
+ }
1282
+
1283
+ match * ty. kind ( ) {
1284
+ ty:: FnDef ( ..) => Sizedness :: Zero ,
1285
+ ty:: Tuple ( tys) => for_list ( tcx, param_env, tys) ,
1286
+ ty:: Array ( _, len) if len. try_eval_target_usize ( tcx, param_env) . is_some_and ( |x| x == 0 ) => Sizedness :: Zero ,
1287
+ ty:: Array ( ty, _) => sizedness_of ( tcx, param_env, ty) ,
1288
+ ty:: Adt ( adt, args) => {
1289
+ let mut iter = adt
1290
+ . variants ( )
1291
+ . iter ( )
1292
+ . map ( |v| for_list ( tcx, param_env, v. fields . iter ( ) . map ( |f| f. ty ( tcx, args) ) ) )
1293
+ . filter ( |x| !x. is_uninhabited ( ) ) ;
1294
+ match iter. next ( ) {
1295
+ None => Sizedness :: Uninhabited ,
1296
+ Some ( Sizedness :: Other ) => Sizedness :: Other ,
1297
+ Some ( _) => {
1298
+ if iter. next ( ) . is_some ( ) {
1299
+ Sizedness :: Other
1300
+ } else {
1301
+ Sizedness :: Zero
1302
+ }
1303
+ } ,
1304
+ }
1305
+ } ,
1306
+ ty:: Closure ( _, args) => for_list ( tcx, param_env, args. as_closure ( ) . upvar_tys ( ) . iter ( ) ) ,
1307
+ ty:: Coroutine ( id, args) => {
1308
+ if for_list ( tcx, param_env, args. as_coroutine ( ) . upvar_tys ( ) . iter ( ) ) . is_uninhabited ( ) {
1309
+ Sizedness :: Uninhabited
1310
+ } else {
1311
+ Sizedness :: Other
1312
+ }
1313
+ } ,
1314
+ ty:: CoroutineClosure ( _, args) => {
1315
+ if for_list ( tcx, param_env, args. as_coroutine_closure ( ) . upvar_tys ( ) . iter ( ) ) . is_uninhabited ( ) {
1316
+ Sizedness :: Uninhabited
1317
+ } else {
1318
+ Sizedness :: Other
1319
+ }
1320
+ } ,
1321
+ ty:: CoroutineWitness ( _, args) => for_list ( tcx, param_env, args. iter ( ) . filter_map ( GenericArg :: as_type) ) ,
1322
+ ty:: Alias ( ..) => {
1323
+ if let Ok ( normalized) = tcx
1324
+ . infer_ctxt ( )
1325
+ . build ( )
1326
+ . at ( & ObligationCause :: dummy ( ) , param_env)
1327
+ . query_normalize ( ty)
1328
+ && normalized. value != ty
1329
+ {
1330
+ sizedness_of ( tcx, param_env, normalized. value )
1331
+ } else {
1332
+ Sizedness :: Other
1333
+ }
1334
+ } ,
1335
+ ty:: Never => Sizedness :: Uninhabited ,
1336
+ ty:: Bool
1337
+ | ty:: Char
1338
+ | ty:: Int ( _)
1339
+ | ty:: Uint ( _)
1340
+ | ty:: Float ( _)
1341
+ | ty:: RawPtr ( ..)
1342
+ | ty:: Ref ( ..)
1343
+ | ty:: FnPtr ( ..)
1344
+ | ty:: Param ( _)
1345
+ | ty:: Bound ( ..)
1346
+ | ty:: Placeholder ( _)
1347
+ | ty:: Infer ( _)
1348
+ | ty:: Error ( _)
1349
+ | ty:: Dynamic ( ..)
1350
+ | ty:: Slice ( ..)
1351
+ | ty:: Str
1352
+ | ty:: Foreign ( _) => Sizedness :: Other ,
1353
+ }
1354
+ }
0 commit comments