Skip to content

Commit 7f1b2c3

Browse files
committed
Fix ICE in pointer layout for DSTs with bogus Sized impls
A bogus `impl<T: ?Sized> Sized for T {}` (rejected as E0322) was processed by the new trait solver (`-Znext-solver=globally`), making DSTs like `[T]` appear sized. This caused `*const [T]` to receive a thin-pointer (Scalar) layout instead of a fat-pointer (ScalarPair) layout. When const evaluation then performed an array-to-slice unsizing coercion and tried to write a ScalarPair value to a Scalar-layout place, it triggered an ICE: "invalid immediate for given destination place: value ScalarPair(...) does not match ABI Scalar(...)" The fix adds a structural cross-check in the pointer layout computation: after `is_sized` returns true, we verify via `struct_tail_for_codegen` (which is purely structural and unaffected by bogus trait impls) that the pointee tail is not a known DST kind (Slice/Str/Dynamic). If it is, we skip the thin-pointer early return and fall through to compute the correct fat-pointer layout.
1 parent a72e2a7 commit 7f1b2c3

3 files changed

Lines changed: 56 additions & 1 deletion

File tree

compiler/rustc_ty_utils/src/layout.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,21 @@ fn layout_of_uncached<'tcx>(
414414
}
415415

416416
if pointee.is_sized(tcx, cx.typing_env) {
417-
return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
417+
// Guard against bogus `impl Sized` declarations (e.g.,
418+
// `impl<T: ?Sized> Sized for T {}`), which are rejected with E0322
419+
// but can still be processed by the trait solver in erroneous code.
420+
// Such impls make DSTs like `[T]` appear sized, causing pointer
421+
// layout to be computed as a thin pointer (Scalar) when it should
422+
// be a fat pointer (ScalarPair). This mismatch causes an ICE during
423+
// const evaluation. We cross-check using the structural tail: if it
424+
// is a known DST kind, the pointer must be fat regardless of what
425+
// the Sized trait says.
426+
let tail = tcx.struct_tail_for_codegen(pointee, cx.typing_env);
427+
if !matches!(tail.kind(), ty::Slice(_) | ty::Str | ty::Dynamic(..)) {
428+
return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
429+
}
430+
// The structural tail is a DST — `is_sized` is unreliable here.
431+
// Fall through to compute the correct fat-pointer layout below.
418432
}
419433

420434
let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ compile-flags: -Znext-solver=globally
2+
3+
// A bogus `impl Sized for T` (rejected with E0322) used to cause an ICE when
4+
// the new trait solver processed it and made DSTs like `[T]` appear sized. This
5+
// caused pointer layout to be computed as a thin-pointer (Scalar) instead of a
6+
// fat-pointer (ScalarPair), and const evaluation of unsafe pointer arithmetic
7+
// inside a `const {}` block would then ICE with:
8+
// "invalid immediate for given destination place: value ScalarPair(...) does
9+
// not match ABI Scalar(...)"
10+
11+
impl<'a, T: ?Sized> Sized for T {}
12+
//~^ ERROR explicit impls for the `Sized` trait are not permitted
13+
//~| ERROR type parameter `T` must be used as the type parameter for some local type
14+
15+
fn main() {
16+
const {
17+
unsafe {
18+
let value = [1, 2];
19+
let _ptr = value.as_ptr().add(2);
20+
}
21+
}
22+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0322]: explicit impls for the `Sized` trait are not permitted
2+
--> $DIR/dont-ice-on-bogus-sized-impl-in-const-block.rs:11:1
3+
|
4+
LL | impl<'a, T: ?Sized> Sized for T {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
6+
7+
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
8+
--> $DIR/dont-ice-on-bogus-sized-impl-in-const-block.rs:11:10
9+
|
10+
LL | impl<'a, T: ?Sized> Sized for T {}
11+
| ^ type parameter `T` must be used as the type parameter for some local type
12+
|
13+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
14+
= note: only traits defined in the current crate can be implemented for a type parameter
15+
16+
error: aborting due to 2 previous errors
17+
18+
Some errors have detailed explanations: E0210, E0322.
19+
For more information about an error, try `rustc --explain E0210`.

0 commit comments

Comments
 (0)