Fix ICE while computing type layout (#14837)

If a type is incomplete, for example if generic parameters are not
available yet, although they are not escaping, its layout may not be
computable. Calling `TyCtxt::layout_of()` would create a delayed bug in
the compiler.

changelog: [`zero_sized_map_values`]: fix ICE

Fixes rust-lang/rust-clippy#14822

r? @Jarcho
This commit is contained in:
Jason Newcomb 2025-05-19 23:33:39 +00:00 committed by GitHub
commit 6753e164be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 39 additions and 7 deletions

View file

@ -51,9 +51,11 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
&& (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
&& let ty::Adt(_, args) = ty.kind()
&& let ty = args.type_at(1)
// Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of
// https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968
&& !ty.has_escaping_bound_vars()
// Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case.
// This might happen when computing a reference/pointer metadata on a type for which we
// cannot check if it is `Sized` or not, such as an incomplete associated type in a
// type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`.
&& !ty.has_non_region_param()
&& let Ok(layout) = cx.layout_of(ty)
&& layout.is_zst()
{

View file

@ -2,6 +2,7 @@
//! This is a reproducer for the ICE 6840: https://github.com/rust-lang/rust-clippy/issues/6840.
//! The ICE is caused by `TyCtxt::layout_of` and `is_normalizable` not being strict enough
#![allow(dead_code)]
#![deny(clippy::zero_sized_map_values)] // For ICE 14822
use std::collections::HashMap;
pub trait Rule {

View file

@ -71,6 +71,27 @@ fn test2(map: HashMap<String, usize>, key: &str) -> HashMap<String, usize> {
todo!();
}
fn issue14822() {
trait Trait {
type T;
}
struct S<T: Trait>(T::T);
// The `delay_bug` happens when evaluating the pointer metadata of `S<T>` which depends on
// whether `T::T` is `Sized`. Since the type alias doesn't have a trait bound of `T: Trait`
// evaluating `T::T: Sized` ultimately fails with `NoSolution`.
type A<T> = HashMap<u32, *const S<T>>;
type B<T> = HashMap<u32, S<T>>;
enum E {}
impl Trait for E {
type T = ();
}
type C = HashMap<u32, *const S<E>>;
type D = HashMap<u32, S<E>>;
//~^ zero_sized_map_values
}
fn main() {
let _: HashMap<String, ()> = HashMap::new();
//~^ zero_sized_map_values

View file

@ -81,7 +81,15 @@ LL | fn test(map: HashMap<String, ()>, key: &str) -> HashMap<String, ()> {
= help: consider using a set instead
error: map with zero-sized value type
--> tests/ui/zero_sized_hashmap_values.rs:75:34
--> tests/ui/zero_sized_hashmap_values.rs:91:14
|
LL | type D = HashMap<u32, S<E>>;
| ^^^^^^^^^^^^^^^^^^
|
= help: consider using a set instead
error: map with zero-sized value type
--> tests/ui/zero_sized_hashmap_values.rs:96:34
|
LL | let _: HashMap<String, ()> = HashMap::new();
| ^^^^^^^
@ -89,7 +97,7 @@ LL | let _: HashMap<String, ()> = HashMap::new();
= help: consider using a set instead
error: map with zero-sized value type
--> tests/ui/zero_sized_hashmap_values.rs:75:12
--> tests/ui/zero_sized_hashmap_values.rs:96:12
|
LL | let _: HashMap<String, ()> = HashMap::new();
| ^^^^^^^^^^^^^^^^^^^
@ -97,12 +105,12 @@ LL | let _: HashMap<String, ()> = HashMap::new();
= help: consider using a set instead
error: map with zero-sized value type
--> tests/ui/zero_sized_hashmap_values.rs:81:12
--> tests/ui/zero_sized_hashmap_values.rs:102:12
|
LL | let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect();
| ^^^^^^^^^^^^^
|
= help: consider using a set instead
error: aborting due to 13 previous errors
error: aborting due to 14 previous errors