Skip to content

rust-analyzer doesn't like zerocopy::KnownLayout on DSTs #18682

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

Closed
allisonkarlitskaya opened this issue Dec 13, 2024 · 6 comments · Fixed by #19106
Closed

rust-analyzer doesn't like zerocopy::KnownLayout on DSTs #18682

allisonkarlitskaya opened this issue Dec 13, 2024 · 6 comments · Fixed by #19106
Assignees
Labels
A-layout Memory layout of types C-bug Category: bug

Comments

@allisonkarlitskaya
Copy link

rust-analyzer version: rust-analyzer 1.83.0 via rust-analyzer-1.83.0-1.fc41.x86_64
rustc version: rustc 1.83.0 (90b35a623 2024-11-26) (Fedora 1.83.0-1.fc41) via rust-1.83.0-1.fc41.x86_64
editor or extension: nvim from Fedora 41: neovim-0.10.2-1.fc41.x86_64
relevant settings:

LSP configs active in this buffer (bufnr: 1) ~
- Language client log: ~/.local/state/nvim/lsp.log
- Detected filetype: `rust`
- 1 client(s) attached to this buffer
- Client: `rust_analyzer` (id: 1, bufnr: [1])
  root directory:    ~/src/reproducer/
  filetypes:         rust
  cmd:               /usr/local/bin/rust-analyzer
  version:           `rust-analyzer 1.85.0-nightly (d4025ee 2024-12-12)`
  executable:        true
  autostart:         true

code snippet to reproduce:

// add your code here
use zerocopy::KnownLayout;

#[derive(KnownLayout)]
#[repr(C)]
struct Flexible {
    header: u32,
    body: [u8],
}

This gets you

1. casting `*mut _` as `*mut __ZerocopyKnownLayoutMaybeUninit` is invalid: vtable kinds may not match [E0606]
2. casting `*mut __ZerocopyKnownLayoutMaybeUninit` as `*mut _` is invalid: vtable kinds may not match [E0606]

but with cargo build it's fine.

This is caused by Flexible being a DST (dynamically sized type). Dropping the variable-sized body: [u8] field makes the problem go away.

I also tried with nightly (rust-analyzer 1.85.0-nightly (d4025ee 2024-12-12)) without improvement.

@allisonkarlitskaya allisonkarlitskaya added the C-bug Category: bug label Dec 13, 2024
@ShoyuVanilla ShoyuVanilla self-assigned this Dec 16, 2024
@lnicola lnicola added the A-layout Memory layout of types label Jan 3, 2025
@sudosilico
Copy link

sudosilico commented Feb 3, 2025

If you don't get any complaints elsewhere from rust-analyzer (only from rustc) when you remove the KnownLayout derive, then a potential workaround is to tell rust-analyzer to ignore the KnownLayout macro:

"rust-analyzer.procMacro.ignored": {
  "zerocopy_derive": ["KnownLayout"]
},

@joshlf
Copy link

joshlf commented Feb 3, 2025

For help in debugging this issue, here's the cargo expand output of the provided code snippet using zerocopy 0.8.15:

Code

Source:

use zerocopy::KnownLayout;

#[derive(KnownLayout)]
#[repr(C)]
struct Flexible {
    header: u32,
    body: [u8],
}

Output of cargo expand:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use zerocopy::KnownLayout;
#[repr(C)]
struct Flexible {
    header: u32,
    body: [u8],
}
const _: () = {
    #[allow(deprecated)]
    #[automatically_derived]
    unsafe impl ::zerocopy::KnownLayout for Flexible
    where
        [u8]: ::zerocopy::KnownLayout,
    {
        fn only_derive_is_allowed_to_implement_this_trait() {}
        type PointerMetadata = <[u8] as ::zerocopy::KnownLayout>::PointerMetadata;
        type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit;
        const LAYOUT: ::zerocopy::DstLayout = {
            use ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize;
            use ::zerocopy::{DstLayout, KnownLayout};
            let repr_align = ::zerocopy::util::macro_util::core_reexport::option::Option::None;
            let repr_packed = ::zerocopy::util::macro_util::core_reexport::option::Option::None;
            DstLayout::new_zst(repr_align)
                .extend(DstLayout::for_type::<u32>(), repr_packed)
                .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed)
                .pad_to_align()
        };
        #[inline(always)]
        fn raw_from_ptr_len(
            bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<u8>,
            meta: Self::PointerMetadata,
        ) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<Self> {
            use ::zerocopy::KnownLayout;
            let trailing = <[u8] as KnownLayout>::raw_from_ptr_len(bytes, meta);
            let slf = trailing.as_ptr() as *mut Self;
            unsafe {
                ::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked(
                    slf,
                )
            }
        }
        #[inline(always)]
        fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
            <[u8]>::pointer_to_metadata(ptr as *mut _)
        }
    }
    #[allow(non_camel_case_types)]
    struct __Zerocopy_Field_header;
    #[allow(non_camel_case_types)]
    struct __Zerocopy_Field_body;
    unsafe impl ::zerocopy::util::macro_util::Field<__Zerocopy_Field_header>
    for Flexible {
        type Type = u32;
    }
    unsafe impl ::zerocopy::util::macro_util::Field<__Zerocopy_Field_body> for Flexible {
        type Type = [u8];
    }
    #[repr(C)]
    #[doc(hidden)]
    #[allow(private_bounds)]
    struct __ZerocopyKnownLayoutMaybeUninit(
        ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit<
            <Flexible as ::zerocopy::util::macro_util::Field<
                __Zerocopy_Field_header,
            >>::Type,
        >,
        <<Flexible as ::zerocopy::util::macro_util::Field<
            __Zerocopy_Field_body,
        >>::Type as ::zerocopy::KnownLayout>::MaybeUninit,
    )
    where
        <Flexible as ::zerocopy::util::macro_util::Field<
            __Zerocopy_Field_body,
        >>::Type: ::zerocopy::KnownLayout;
    unsafe impl ::zerocopy::KnownLayout for __ZerocopyKnownLayoutMaybeUninit
    where
        <Flexible as ::zerocopy::util::macro_util::Field<
            __Zerocopy_Field_body,
        >>::Type: ::zerocopy::KnownLayout,
    {
        #[allow(clippy::missing_inline_in_public_items)]
        fn only_derive_is_allowed_to_implement_this_trait() {}
        type PointerMetadata = <Flexible as ::zerocopy::KnownLayout>::PointerMetadata;
        type MaybeUninit = Self;
        const LAYOUT: ::zerocopy::DstLayout = <Flexible as ::zerocopy::KnownLayout>::LAYOUT;
        #[inline(always)]
        fn raw_from_ptr_len(
            bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<u8>,
            meta: Self::PointerMetadata,
        ) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<Self> {
            use ::zerocopy::KnownLayout;
            let trailing = <<<Flexible as ::zerocopy::util::macro_util::Field<
                __Zerocopy_Field_body,
            >>::Type as ::zerocopy::KnownLayout>::MaybeUninit as KnownLayout>::raw_from_ptr_len(
                bytes,
                meta,
            );
            let slf = trailing.as_ptr() as *mut Self;
            unsafe {
                ::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked(
                    slf,
                )
            }
        }
        #[inline(always)]
        fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
            <<<Flexible as ::zerocopy::util::macro_util::Field<
                __Zerocopy_Field_body,
            >>::Type as ::zerocopy::KnownLayout>::MaybeUninit>::pointer_to_metadata(
                ptr as *mut _,
            )
        }
    }
};

@ShoyuVanilla
Copy link
Member

I've been planning to resolve this issue, but couldn't make time for it 😅 I'll work on this today

@ShoyuVanilla
Copy link
Member

ShoyuVanilla commented Feb 6, 2025

It seems that r-a is failing to infer the projection types in the definition of __ZerocopyKnownLayoutMaybeUninit.
Replacing them with direct, actual type removes those false positive diagnostics.
r-a fails to infer projection types in some places, and as we are migrating its trait solver from chalk to rustc's next-gen solver, this might be mitigated in future.
I'll add a code that skips this diagnostics if we are failing to infer the projection types.

edit) It looks like that I've missed resolving the projection type 😅 I'll fix this soon.

Sorry for the inconveniences and delayed fix

@cloneable
Copy link

There's still a problem with KnownLayout when the DST is wrapped:

use zerocopy::KnownLayout;

#[derive(KnownLayout)]
#[repr(C)]
pub struct Dst([u8]);

#[derive(KnownLayout)]
#[repr(C)]
pub struct Struct {
    pub dst: Dst,
}
cannot cast thin pointer `*mut __ZerocopyKnownLayoutMaybeUninit` to fat pointer `*mut _` rust-analyzer[E0607]

rust-analyzer 1.85.1 (4eb16125 2025-03-15)

No problem with rustc.

@ShoyuVanilla
Copy link
Member

There's still a problem with KnownLayout when the DST is wrapped:

I've addressed a new issue for this and a new PR fixing it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-layout Memory layout of types C-bug Category: bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants