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

Cycle detected when evaluating trait selection obligation #2116

Closed
zhoukezi opened this issue Dec 2, 2024 · 6 comments
Closed

Cycle detected when evaluating trait selection obligation #2116

zhoukezi opened this issue Dec 2, 2024 · 6 comments
Assignees
Labels
bug Something isn't working

Comments

@zhoukezi
Copy link

zhoukezi commented Dec 2, 2024

With zerocopy 0.8.11, the following code failed to compile:

use zerocopy::*;

#[derive(KnownLayout)]
#[repr(C)]
pub struct Dummy([u8; Self::CONST]);

impl Dummy {
    const CONST: usize = 42;
}
error[E0391]: cycle detected when evaluating trait selection obligation `_::__ZerocopyKnownLayoutMaybeUninit: core::iter::traits::collect::IntoIterator`
  |
note: ...which requires evaluating type-level constant...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires const-evaluating + checking `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires caching mir of `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}` for CTFE...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires elaborating drops for `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires borrow-checking `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires const checking `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires building MIR for `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires match-checking `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:23
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                       ^^^^^^^^^^^
note: ...which requires type-checking `_::__ZerocopyKnownLayoutMaybeUninit::0::{constant#0}`...
 --> src/lib.rs:5:29
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                             ^^^^^
  = note: ...which again requires evaluating trait selection obligation `_::__ZerocopyKnownLayoutMaybeUninit: core::iter::traits::collect::IntoIterator`, completing the cycle
note: cycle used when type-checking `_::<impl at src/lib.rs:3:10: 3:21>::{constant#0}`
 --> src/lib.rs:5:29
  |
5 | pub struct Dummy([u8; Self::CONST]);
  |                             ^^^^^
  = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

For more information about this error, try `rustc --explain E0391`.

This compiles on 0.8.10.

> rustc --version
rustc 1.83.0 (90b35a623 2024-11-26)
> cargo --version
cargo 1.83.0 (5ffbef321 2024-10-29)
> cat Cargo.toml
[package]
name = "sandbox"
version = "0.1.0"
edition = "2021"

[dependencies]
#zerocopy = { version = "=0.8.11", features = ["derive"] }
zerocopy = { version = "=0.8.10", features = ["derive"] }
@joshlf
Copy link
Member

joshlf commented Dec 2, 2024

Thanks for reporting this! We'll take a look.

@joshlf joshlf added the bug Something isn't working label Dec 2, 2024
@jswrenn
Copy link
Collaborator

jswrenn commented Dec 2, 2024

This is definitely a bug on our end, though the rustc error message is also a red herring. Here's a self-contained repro:

trait KnownLayout {
    type MaybeUninit;
}

impl KnownLayout for u8 {
    type MaybeUninit = core::mem::MaybeUninit<Self>;
}

impl<const N: usize, T> KnownLayout for [T; N]
where
    T: KnownLayout
{
    type MaybeUninit = [<T as KnownLayout>::MaybeUninit; N];
}

#[repr(C)]
pub struct Dummy([u8; Self::CONST]);

impl Dummy {
    const CONST: usize = 42;
}

const _: () = {
    #[repr(C)]
    struct DummyMaybeUninit(<[u8; Self::CONST] as KnownLayout>::MaybeUninit);

    impl KnownLayout for Dummy {
        type MaybeUninit = DummyMaybeUninit;
    }
};

The issue, here, is this line:

struct DummyMaybeUninit(<[u8; Self::CONST] as KnownLayout>::MaybeUninit);

...because Self takes on a different type when emplaced in DummyMaybeUninit. The DummyMaybeUninit doesn't have an associated CONST, and so this code contains a type error.

@jswrenn
Copy link
Collaborator

jswrenn commented Dec 2, 2024

We can probably fix this by replacing occurrences of Self with #ident #ty_generics in __ZerocopyKnownLayoutMaybeUninit.

@jswrenn
Copy link
Collaborator

jswrenn commented Dec 3, 2024

Hm, that approach is complicated by the fact that const exprs can be arbitrarily complicated and define new types in which Self takes on a different meaning; e.g.:

struct Headache([u8; {
    struct Migraine;

    impl Migraine {
        const A: usize = 21;
        const B: usize = 21;
        const LEN: usize = Self::A + Self::B;
    }

    impl Headache {
        const A: usize = Migraine::LEN;
        const B: usize = Migraine::LEN;
        const LEN: usize = Self::A + Self::B;
    }

    Self::LEN
}]);

@jswrenn
Copy link
Collaborator

jswrenn commented Dec 3, 2024

Perhaps, instead, we can add a TrailingField associated type to KnownLayout and reference that instead. It's a layer of indirection that will make the safety proofs more annoying, but it should do the trick.

jswrenn added a commit that referenced this issue Dec 3, 2024
jswrenn added a commit that referenced this issue Dec 3, 2024
jswrenn added a commit that referenced this issue Dec 3, 2024
jswrenn added a commit that referenced this issue Dec 3, 2024
jswrenn added a commit that referenced this issue Dec 3, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<const N: usize> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    impl Field<0> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 3, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<const N: usize> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    impl Field<0> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<const N: usize> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    impl Field<0> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<const N: usize> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    impl Field<0> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<const N: usize> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    impl Field<0> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<const N: usize> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    impl Field<0> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<const N: usize> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    impl Field<0> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
jswrenn added a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
github-merge-queue bot pushed a commit that referenced this issue Dec 4, 2024
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116
@joshlf
Copy link
Member

joshlf commented Dec 5, 2024

Fixed by #2127 and published in 0.8.13.

@joshlf joshlf closed this as completed Dec 5, 2024
google-pr-creation-bot pushed a commit to google-pr-creation-bot/zerocopy that referenced this issue Feb 6, 2025
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes google#2116
github-merge-queue bot pushed a commit that referenced this issue Feb 6, 2025
This commit revises the `KnownLayout` derive on `repr(C)` target structs to
preserve the correct resolution of `Self` when constructing
`__ZerocopyKnownLayoutMaybeUninit`. This type contains a `MaybeUninit` version
of each of the target struct's field types. Previously, it achieved this by
simply copying the tokens corresponding to field types from the definition of
the target struct into the definition of `__ZerocopyKnownLayoutMaybeUninit`

However, on types like this:

    #[repr(C)]
    struct Struct([u8; Self::N]);

…this approach is insufficient. Pasted into `__ZerocopyKnownLayoutMaybeUninit`,
`Self` ceases to refer to the target struct and instead refers to
`__ZerocopyKnownLayoutMaybeUninit`.

To preserve `Self` hygiene, this commit defines a struct for projecting the
field types of the target struct based on their index:

    pub unsafe trait Field<Index> {
        type Type: ?Sized;
    }

…then implements it for each of the field types of the target struct; e.g.:

    struct Index<const N: usize>;

    impl Field<Index<0>> for Struct {
        type Type = [u8; Self::N];
    }

With this, the fields of `__ZerocopyKnownLayoutMaybeUninit` can be defined
hygienically; e.g., as `<Struct as Field<0>>::Type`.

Fixes #2116

Co-authored-by: Jack Wrenn <jswrenn@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants