Skip to content

unsized_fn_params should not accept types that don't have a dynamically fixed size (such as extern types) #115709

Description

@RalfJung

The following code should not be accepted:

#![feature(extern_types)]
#![feature(unsized_fn_params)]

extern {
    type E;
}

fn test(e: E) {}

fn calltest(e: Box<E>) {
    test(*e)
}

In terms of MIR semantics I think we want to view a function call as making copies of its arguments. This requires at least dynamically determining the size of the argument, and therefore we shouldn't accept extern type arguments.

I was extremely surprised earlier today when I learned that this code is getting accepted.

There is no generic bound to distinguish extern types from other unsized types, so the options we have are

  • require the unsized type to be concrete enough that we can determine its tail, and ensure it is not extern
  • raise the error during monomorphization / codegen

Trying to actually build any such code will lead to ICEs such as

error: internal compiler error: compiler/rustc_codegen_llvm/src/type_of.rs:306:13: TyAndLayout::scalar_pair_element_llty(TyAndLayout { ty: *mut E, layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 0..=18446744073709551615 }), fields: Primitive, largest_niche: None, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes) } }): not applicable

or

thread 'rustc' panicked at compiler/rustc_codegen_llvm/src/builder.rs:491:9:
assertion `left == right` failed
  left: false
 right: true

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Sep 9, 2023
  2. SNCPlay42 commented on Sep 9, 2023

    @SNCPlay42
    Contributor

    See also #79409.

    There is no generic bound to distinguish extern types from other unsized types

    rust-lang/rfcs#2984 and rust-lang/rfcs#3396 are open RFCs that attempt to address this.

  3. RalfJung commented on Sep 9, 2023

    @RalfJung
    MemberAuthor

    Unfortunately just rejecting locals/arguments that are not known to be dyn-sized as a MIR pass does not work: the forget_unsized function in the standard library would stop compiling.

    So currently something post-monomorphization is the only option. Is there even some place that check could be put without being duplicated across all codegen backends (and Miri)?

  4. changed the title [-]unsized_fn_params should not accept types that don't have a dynamically fixed size[/-] [+]unsized_fn_params should not accept types that don't have a dynamically fixed size (such as `extern` types)[/+] on Sep 10, 2023
  5. added 5 commits that reference this issue on Sep 11, 2023
  6. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Sep 19, 2023
  7. added 2 commits that reference this issue on Sep 24, 2023
  8. RalfJung commented on Dec 2, 2023

    @RalfJung
    MemberAuthor

    In #116115 we agreed that this is not worth a post-mono check; this needs proper design to find a way that makes this work without a post-mono check. So for now we are living with the ICEs.

  9. added a commit that references this issue on Dec 4, 2023
  10. added a commit that references this issue on Dec 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    F-extern_types`#![feature(extern_types)]`F-unsized_fn_params`#![feature(unsized_fn_params)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions