Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot transmute between ZST and zero-sized generic array #98104

Open
lukas-code opened this issue Jun 14, 2022 · 1 comment
Open

Cannot transmute between ZST and zero-sized generic array #98104

lukas-code opened this issue Jun 14, 2022 · 1 comment
Labels
A-array Area: `[T; N]` C-bug Category: This is a bug.

Comments

@lukas-code
Copy link
Member

I tried this code: (Playground)

struct GenericZst<T> {
    a: [T; 0],
}

fn foo<T>() -> GenericZst<T> {
    unsafe { ::core::mem::transmute::<(), GenericZst<T>>(()) }
}

I expected this to compile, because [T; 0] is always zero-sized.

Instead, it fails to compile with this error:

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src/lib.rs:6:14
  |
6 |     unsafe { ::core::mem::transmute::<(), GenericZst<T>>(()) }
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: source type: `()` (0 bits)
  = note: target type: `GenericZst<T>` (size can vary because of T)

For more information about this error, try `rustc --explain E0512`.
error: could not compile `playground` due to previous error

Meta

rustc --version --verbose:

rustc 1.63.0-nightly (ca122c7eb 2022-06-13)
binary: rustc
commit-hash: ca122c7ebb3ab50149c9d3d24ddb59c252b32272
commit-date: 2022-06-13
host: x86_64-unknown-linux-gnu
release: 1.63.0-nightly
LLVM version: 14.0.5

somewhat related: #98064

@lukas-code lukas-code added the C-bug Category: This is a bug. label Jun 14, 2022
@workingjubilee workingjubilee added the A-array Area: `[T; N]` label Mar 7, 2023
dvdhrm added a commit to dvdhrm/rust that referenced this issue Jul 24, 2023
Extend the `SizeSkeleton` evaluator to shortcut zero-sized arrays, thus
considering `[T; 0]` to have a compile-time fixed-size of 0.

The existing evaluator already deals with generic arrays under the
feature-guard `transmute_const_generics`. However, it merely allows
comparing fixed-size types with fixed-size types, and generic types with
generic types. For generic types, it merely compares whether their
arguments match (ordering them first). Even if their exact sizes are not
known at compile time, it can ensure that they will eventually be the
same.

This patch extends this by shortcutting the size-evaluation of zero
sized arrays and thus allowing size comparisons of `()` with `[T; 0]`,
where one contains generics and the other does not.

This code is guarded by `transmute_const_generics` (rust-lang#109929), even
though it is unclear whether it should be. However, this assumes that a
separate stabilization PR is required to move this out of the feature
guard.

Initially reported in rust-lang#98104.
@dvdhrm
Copy link
Contributor

dvdhrm commented Jul 24, 2023

I would argue that this should not be considered a bug, but that it works as intended. I started tackling this in #114009, and it is definitely possible to implement this. However, it is unclear whether we can stabilize this in its current state and whether it wouldn't require an RFC.

The compiler currently handles most type-layout aspects in a compound way. That is, size, alignment, abi, etc. of a type is tracked in a single Layout object (or LayoutS, fwiw). If any of the layout properties cannot be determined, none of the properties is made available. On the flip-side, this means a layout property can only be used by the compiler if all layout properties are well defined.

In this situation that means that the compiler can only consider the size of the generic array if its alignment is also known. Since the alignment of generic arrays is not fixed, the compiler will also refuse to reason about its size.

There is a feature-flag transmute_generic_consts (#109929) which untangles size-calculations from layout-calculations (used in several places, not just transmute). It uses a SizeSkeleton structure that allows calculating type-sizes independent of their layout. Furthermore, it even allows comparing type-sizes of non-fixed generics through simple type-comparisons. However, there is no agreement on whether this can be stabilized as it is. @lcnr raised concerns and mentioned transmutability (#99571) as possible alternative.

From a user perspective I can understand that this transmute should be valid rust code. However, I can also see that layout calculations might have cascading effects. I could easily get transmutes work for zero-sized generic arrays (see #114009). However, for true transmute support this would need to be extended to propagate through compound types with such arrays, or through newtypes, etc. And then it might also affect calculations of repr(transparent) (which also considers zero-sized fields, but is also affected by alignment), or nonnull_layout_guaranteed (which propagates its optimization through newtypes).

Maybe someone from the compiler team can comment on possible future plans for this. But as an outsider, I feel like putting effort into implementing this just to be blocked by transmute_generic_consts seems a bit wasted. Is there a future for SizeSkeleton? Is it possible to implement extensions of SizeSkeleton without the feature flag? Does an implementation of said transmute extensions need an RFC first?

workingjubilee added a commit to workingjubilee/rustc that referenced this issue Mar 7, 2024
compiler: allow transmute of ZST arrays with generics

Extend the `SizeSkeleton` evaluator to shortcut zero-sized arrays, thus considering `[T; 0]` to have a compile-time fixed-size of 0.

The existing evaluator already deals with generic arrays under the feature-guard `transmute_const_generics`. However, it merely allows comparing fixed-size types with fixed-size types, and generic types with generic types. For generic types, it merely compares whether their arguments match (ordering them first). Even if their exact sizes are not known at compile time, it can ensure that they will eventually be the same.

This patch extends this by shortcutting the size-evaluation of zero sized arrays and thus allowing size comparisons of `()` with `[T; 0]`, where one contains generics and the other does not.

This code is guarded by `transmute_const_generics` (rust-lang#109929), even though it is unclear whether it should be. However, this assumes that a separate stabilization PR is required to move this out of the feature guard.

Initially reported in rust-lang#98104.
matthiaskrgr pushed a commit to matthiaskrgr/rust that referenced this issue Mar 22, 2024
Extend the `SizeSkeleton` evaluator to shortcut zero-sized arrays, thus
considering `[T; 0]` to have a compile-time fixed-size of 0.

The existing evaluator already deals with generic arrays under the
feature-guard `transmute_const_generics`. However, it merely allows
comparing fixed-size types with fixed-size types, and generic types with
generic types. For generic types, it merely compares whether their
arguments match (ordering them first). Even if their exact sizes are not
known at compile time, it can ensure that they will eventually be the
same.

This patch extends this by shortcutting the size-evaluation of zero
sized arrays and thus allowing size comparisons of `()` with `[T; 0]`,
where one contains generics and the other does not.

This code is guarded by `transmute_const_generics` (rust-lang#109929), even
though it is unclear whether it should be. However, this assumes that a
separate stabilization PR is required to move this out of the feature
guard.

Initially reported in rust-lang#98104.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Mar 22, 2024
compiler: allow transmute of ZST arrays with generics

Extend the `SizeSkeleton` evaluator to shortcut zero-sized arrays, thus considering `[T; 0]` to have a compile-time fixed-size of 0.

The existing evaluator already deals with generic arrays under the feature-guard `transmute_const_generics`. However, it merely allows comparing fixed-size types with fixed-size types, and generic types with generic types. For generic types, it merely compares whether their arguments match (ordering them first). Even if their exact sizes are not known at compile time, it can ensure that they will eventually be the same.

This patch extends this by shortcutting the size-evaluation of zero sized arrays and thus allowing size comparisons of `()` with `[T; 0]`, where one contains generics and the other does not.

This code is guarded by `transmute_const_generics` (rust-lang#109929), even though it is unclear whether it should be. However, this assumes that a separate stabilization PR is required to move this out of the feature guard.

Initially reported in rust-lang#98104.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Mar 23, 2024
Rollup merge of rust-lang#114009 - dvdhrm:pr/transmzst, r=pnkfelix

compiler: allow transmute of ZST arrays with generics

Extend the `SizeSkeleton` evaluator to shortcut zero-sized arrays, thus considering `[T; 0]` to have a compile-time fixed-size of 0.

The existing evaluator already deals with generic arrays under the feature-guard `transmute_const_generics`. However, it merely allows comparing fixed-size types with fixed-size types, and generic types with generic types. For generic types, it merely compares whether their arguments match (ordering them first). Even if their exact sizes are not known at compile time, it can ensure that they will eventually be the same.

This patch extends this by shortcutting the size-evaluation of zero sized arrays and thus allowing size comparisons of `()` with `[T; 0]`, where one contains generics and the other does not.

This code is guarded by `transmute_const_generics` (rust-lang#109929), even though it is unclear whether it should be. However, this assumes that a separate stabilization PR is required to move this out of the feature guard.

Initially reported in rust-lang#98104.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-array Area: `[T; N]` C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants