@@ -15,7 +15,7 @@ use rustc_lint::LateContext;
15
15
use rustc_middle:: mir:: interpret:: Scalar ;
16
16
use rustc_middle:: mir:: ConstValue ;
17
17
use rustc_middle:: traits:: EvaluationResult ;
18
- use rustc_middle:: ty:: layout:: ValidityRequirement ;
18
+ use rustc_middle:: ty:: layout:: { LayoutOf , ValidityRequirement } ;
19
19
use rustc_middle:: ty:: {
20
20
self , AdtDef , AliasTy , AssocItem , AssocKind , Binder , BoundRegion , FnSig , GenericArg , GenericArgKind ,
21
21
GenericArgsRef , GenericParamDefKind , IntTy , ParamEnv , Region , RegionKind , TraitRef , Ty , TyCtxt , TypeSuperVisitable ,
@@ -353,50 +353,6 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
353
353
}
354
354
}
355
355
356
- // FIXME: Per https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
357
- // this function can be removed once the `normalize` method does not panic when normalization does
358
- // not succeed
359
- /// Checks if `Ty` is normalizable. This function is useful
360
- /// to avoid crashes on `layout_of`.
361
- pub fn is_normalizable < ' tcx > ( cx : & LateContext < ' tcx > , param_env : ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> bool {
362
- is_normalizable_helper ( cx, param_env, ty, & mut FxHashMap :: default ( ) )
363
- }
364
-
365
- fn is_normalizable_helper < ' tcx > (
366
- cx : & LateContext < ' tcx > ,
367
- param_env : ParamEnv < ' tcx > ,
368
- ty : Ty < ' tcx > ,
369
- cache : & mut FxHashMap < Ty < ' tcx > , bool > ,
370
- ) -> bool {
371
- if let Some ( & cached_result) = cache. get ( & ty) {
372
- return cached_result;
373
- }
374
- // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
375
- cache. insert ( ty, false ) ;
376
- let infcx = cx. tcx . infer_ctxt ( ) . build ( ) ;
377
- let cause = ObligationCause :: dummy ( ) ;
378
- let result = if infcx. at ( & cause, param_env) . query_normalize ( ty) . is_ok ( ) {
379
- match ty. kind ( ) {
380
- ty:: Adt ( def, args) => def. variants ( ) . iter ( ) . all ( |variant| {
381
- variant
382
- . fields
383
- . iter ( )
384
- . all ( |field| is_normalizable_helper ( cx, param_env, field. ty ( cx. tcx , args) , cache) )
385
- } ) ,
386
- _ => ty. walk ( ) . all ( |generic_arg| match generic_arg. unpack ( ) {
387
- GenericArgKind :: Type ( inner_ty) if inner_ty != ty => {
388
- is_normalizable_helper ( cx, param_env, inner_ty, cache)
389
- } ,
390
- _ => true , // if inner_ty == ty, we've already checked it
391
- } ) ,
392
- }
393
- } else {
394
- false
395
- } ;
396
- cache. insert ( ty, result) ;
397
- result
398
- }
399
-
400
356
/// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any
401
357
/// integer or floating-point number type). For checking aggregation of primitive types (e.g.
402
358
/// tuples and slices of primitive type) see `is_recursively_primitive_type`
@@ -977,11 +933,12 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
977
933
978
934
/// Comes up with an "at least" guesstimate for the type's size, not taking into
979
935
/// account the layout of type parameters.
936
+ ///
937
+ /// This function will ICE if called with an improper `ParamEnv`. This can happen
938
+ /// when linting in when item, but the type is retrieved from a different item
939
+ /// without instantiating the generic arguments. It can also happen when linting a
940
+ /// type alias as those do not have a `ParamEnv`.
980
941
pub fn approx_ty_size < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> u64 {
981
- use rustc_middle:: ty:: layout:: LayoutOf ;
982
- if !is_normalizable ( cx, cx. param_env , ty) {
983
- return 0 ;
984
- }
985
942
match ( cx. layout_of ( ty) . map ( |layout| layout. size . bytes ( ) ) , ty. kind ( ) ) {
986
943
( Ok ( size) , _) => size,
987
944
( Err ( _) , ty:: Tuple ( list) ) => list. iter ( ) . map ( |t| approx_ty_size ( cx, t) ) . sum ( ) ,
@@ -1340,3 +1297,91 @@ pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) ->
1340
1297
_ => None ,
1341
1298
}
1342
1299
}
1300
+
1301
+ #[ derive( Clone , Copy ) ]
1302
+ pub enum Sizedness {
1303
+ /// The type is uninhabited. (e.g. `!`)
1304
+ Uninhabited ,
1305
+ /// The type is zero-sized.
1306
+ Zero ,
1307
+ /// The type has some other size or an unknown size.
1308
+ Other ,
1309
+ }
1310
+ impl Sizedness {
1311
+ pub fn is_zero ( self ) -> bool {
1312
+ matches ! ( self , Self :: Zero )
1313
+ }
1314
+
1315
+ pub fn is_uninhabited ( self ) -> bool {
1316
+ matches ! ( self , Self :: Uninhabited )
1317
+ }
1318
+ }
1319
+
1320
+ /// Calculates the sizedness of a type.
1321
+ pub fn sizedness_of < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> Sizedness {
1322
+ fn is_zst < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , ty : Ty < ' tcx > ) -> bool {
1323
+ match * ty. kind ( ) {
1324
+ ty:: FnDef ( ..) | ty:: Never => true ,
1325
+ ty:: Tuple ( tys) => tys. iter ( ) . all ( |ty| is_zst ( tcx, param_env, ty) ) ,
1326
+ // Zero length arrays are always zero-sized, even for uninhabited types.
1327
+ ty:: Array ( _, len) if len. try_eval_target_usize ( tcx, param_env) . is_some_and ( |x| x == 0 ) => true ,
1328
+ ty:: Array ( ty, _) | ty:: Pat ( ty, _) => is_zst ( tcx, param_env, ty) ,
1329
+ ty:: Adt ( adt, args) => {
1330
+ let mut iter = adt. variants ( ) . iter ( ) . filter ( |v| {
1331
+ !v. fields
1332
+ . iter ( )
1333
+ . any ( |f| f. ty ( tcx, args) . is_privately_uninhabited ( tcx, param_env) )
1334
+ } ) ;
1335
+ let is_zst = iter. next ( ) . map_or ( true , |v| {
1336
+ v. fields . iter ( ) . all ( |f| is_zst ( tcx, param_env, f. ty ( tcx, args) ) )
1337
+ } ) ;
1338
+ is_zst && iter. next ( ) . is_none ( )
1339
+ } ,
1340
+ ty:: Closure ( _, args) => args
1341
+ . as_closure ( )
1342
+ . upvar_tys ( )
1343
+ . iter ( )
1344
+ . all ( |ty| is_zst ( tcx, param_env, ty) ) ,
1345
+ ty:: CoroutineWitness ( _, args) => args
1346
+ . iter ( )
1347
+ . filter_map ( GenericArg :: as_type)
1348
+ . all ( |ty| is_zst ( tcx, param_env, ty) ) ,
1349
+ ty:: Alias ( ..) => {
1350
+ if let Ok ( normalized) = tcx. try_normalize_erasing_regions ( param_env, ty)
1351
+ && normalized != ty
1352
+ {
1353
+ is_zst ( tcx, param_env, normalized)
1354
+ } else {
1355
+ false
1356
+ }
1357
+ } ,
1358
+ ty:: Bool
1359
+ | ty:: Char
1360
+ | ty:: Int ( _)
1361
+ | ty:: Uint ( _)
1362
+ | ty:: Float ( _)
1363
+ | ty:: RawPtr ( ..)
1364
+ | ty:: Ref ( ..)
1365
+ | ty:: FnPtr ( ..)
1366
+ | ty:: Param ( _)
1367
+ | ty:: Bound ( ..)
1368
+ | ty:: Placeholder ( _)
1369
+ | ty:: Infer ( _)
1370
+ | ty:: Error ( _)
1371
+ | ty:: Dynamic ( ..)
1372
+ | ty:: Slice ( ..)
1373
+ | ty:: Str
1374
+ | ty:: Foreign ( _)
1375
+ | ty:: Coroutine ( ..)
1376
+ | ty:: CoroutineClosure ( ..) => false ,
1377
+ }
1378
+ }
1379
+
1380
+ if ty. is_privately_uninhabited ( tcx, param_env) {
1381
+ Sizedness :: Uninhabited
1382
+ } else if is_zst ( tcx, param_env, ty) {
1383
+ Sizedness :: Zero
1384
+ } else {
1385
+ Sizedness :: Other
1386
+ }
1387
+ }
0 commit comments