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

repr(transparent) wrapper with uninhabited ZST has different return ABI than wrapped field. #135802

Closed
zachs18 opened this issue Jan 21, 2025 · 24 comments · Fixed by #136985
Closed
Labels
A-ABI Area: Concerning the application binary interface (ABI) A-miri Area: The miri tool A-repr Area: the `#[repr(stuff)]` attribute C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@zachs18
Copy link
Contributor

zachs18 commented Jan 21, 2025

This code ICEs Miri, the normal compiler compiles this without complaint, but might be miscompiling it1, though a const version using -Zunleash-the-miri-inside-of-you does ICE the compiler.

Code

type Field = u8; // any non-1ZST probably
#[repr(transparent)]
struct Foo {
  _zst: std::convert::Infallible,
  _field: Field,
}
fn foo() -> Foo {
  panic!()
}
fn main() {
  let f: fn() -> Foo = foo;
  let f: fn() -> Field = unsafe { std::mem::transmute(f) };
  f();
}  
cargo +nightly miri run
modified version using `-Zunleash-the-miri-inside-of-you` that ICEs rustc
type Field = u8; // any non-1ZST probably
#[repr(transparent)]
struct Foo {
  _zst: std::convert::Infallible,
  _field: Field,
}
const fn foo() -> Foo {
    panic!()
}
fn main() {
    const {
        let f: fn() -> Foo = foo;
        let f: fn() -> Field = unsafe { std::mem::transmute(f) };
        f();
    }
}
RUSTFLAGS="-Zunleash-the-miri-inside-of-you" cargo +nightly run

Backtrace:

thread 'rustc' panicked at compiler/rustc_const_eval/src/interpret/call.rs:253:13:
assertion failed: caller_abi.eq_abi(callee_abi)
stack backtrace:
   0:     0x7e3cb9b652a5 - std::backtrace::Backtrace::create::h8985a2f6ef2eb84f
   1:     0x7e3cb80e39f5 - std::backtrace::Backtrace::force_capture::h9a611efb2a942dc9
   2:     0x7e3cb725a4e0 - std[4faddc71fb6fa0e5]::panicking::update_hook::<alloc[c55780341d73682]::boxed::Box<rustc_driver_impl[80a9ca323d3e3890]::install_ice_hook::{closure#1}>>::{closure#0}
   3:     0x7e3cb80fc333 - std::panicking::rust_panic_with_hook::hf47d9e178e038701
   4:     0x7e3cb80fbff6 - std::panicking::begin_panic_handler::{{closure}}::hd9b9f2d3dd54e86c
   5:     0x7e3cb80f99e9 - std::sys::backtrace::__rust_end_short_backtrace::h342bb668fc58e319
   6:     0x7e3cb80fbced - rust_begin_unwind
   7:     0x7e3cb4da8db0 - core::panicking::panic_fmt::hb3cd74fdfc019257
   8:     0x7e3cb5897b9c - core::panicking::panic::h92e08174b9fe42d1
   9:     0x7e3cb92c11bb - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<rustc_const_eval[e3d2a21e14ef9d90]::const_eval::machine::CompileTimeMachine>>::init_stack_frame
  10:     0x7e3cb92bde11 - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<rustc_const_eval[e3d2a21e14ef9d90]::const_eval::machine::CompileTimeMachine>>::init_fn_call
  11:     0x7e3cb6314e8f - rustc_const_eval[e3d2a21e14ef9d90]::const_eval::eval_queries::eval_to_allocation_raw_provider
  12:     0x7e3cb9041f5c - rustc_query_impl[283282ac12660651]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[283282ac12660651]::query_impl::eval_to_allocation_raw::dynamic_query::{closure#2}::{closure#0}, rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 24usize]>>
  13:     0x7e3cb9041fb7 - <rustc_query_impl[283282ac12660651]::query_impl::eval_to_allocation_raw::dynamic_query::{closure#2} as core[b8d8efd06dd057cd]::ops::function::FnOnce<(rustc_middle[d099a8b084c78b18]::ty::context::TyCtxt, rustc_middle[d099a8b084c78b18]::ty::PseudoCanonicalInput<rustc_middle[d099a8b084c78b18]::mir::interpret::GlobalId>)>>::call_once
  14:     0x7e3cb90406be - rustc_query_system[57efd1c10fae1b2]::query::plumbing::try_execute_query::<rustc_query_impl[283282ac12660651]::DynamicConfig<rustc_query_system[57efd1c10fae1b2]::query::caches::DefaultCache<rustc_middle[d099a8b084c78b18]::ty::PseudoCanonicalInput<rustc_middle[d099a8b084c78b18]::mir::interpret::GlobalId>, rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 24usize]>>, false, false, false>, rustc_query_impl[283282ac12660651]::plumbing::QueryCtxt, true>
  15:     0x7e3cb903fffd - rustc_query_impl[283282ac12660651]::query_impl::eval_to_allocation_raw::get_query_incr::__rust_end_short_backtrace
  16:     0x7e3cb904475f - rustc_const_eval[e3d2a21e14ef9d90]::const_eval::eval_queries::eval_to_const_value_raw_provider
  17:     0x7e3cb9044554 - rustc_query_impl[283282ac12660651]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[283282ac12660651]::query_impl::eval_to_const_value_raw::dynamic_query::{closure#2}::{closure#0}, rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 24usize]>>
  18:     0x7e3cb904450d - <rustc_query_impl[283282ac12660651]::query_impl::eval_to_const_value_raw::dynamic_query::{closure#2} as core[b8d8efd06dd057cd]::ops::function::FnOnce<(rustc_middle[d099a8b084c78b18]::ty::context::TyCtxt, rustc_middle[d099a8b084c78b18]::ty::PseudoCanonicalInput<rustc_middle[d099a8b084c78b18]::mir::interpret::GlobalId>)>>::call_once
  19:     0x7e3cb903f2e6 - rustc_query_system[57efd1c10fae1b2]::query::plumbing::try_execute_query::<rustc_query_impl[283282ac12660651]::DynamicConfig<rustc_query_system[57efd1c10fae1b2]::query::caches::DefaultCache<rustc_middle[d099a8b084c78b18]::ty::PseudoCanonicalInput<rustc_middle[d099a8b084c78b18]::mir::interpret::GlobalId>, rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 24usize]>>, false, true, false>, rustc_query_impl[283282ac12660651]::plumbing::QueryCtxt, true>
  20:     0x7e3cb903ebc7 - rustc_query_impl[283282ac12660651]::query_impl::eval_to_const_value_raw::get_query_incr::__rust_end_short_backtrace
  21:     0x7e3cb95e110b - <rustc_middle[d099a8b084c78b18]::ty::context::TyCtxt>::const_eval_resolve
  22:     0x7e3cb5825b39 - <rustc_mir_transform[e7af90bdb15a3f20]::known_panics_lint::ConstPropagator as rustc_middle[d099a8b084c78b18]::mir::visit::Visitor>::visit_operand
  23:     0x7e3cb5829080 - <rustc_mir_transform[e7af90bdb15a3f20]::known_panics_lint::ConstPropagator as rustc_middle[d099a8b084c78b18]::mir::visit::Visitor>::visit_assign
  24:     0x7e3cb582799b - <rustc_mir_transform[e7af90bdb15a3f20]::known_panics_lint::ConstPropagator as rustc_middle[d099a8b084c78b18]::mir::visit::Visitor>::visit_body
  25:     0x7e3cb95f79f9 - <rustc_mir_transform[e7af90bdb15a3f20]::known_panics_lint::KnownPanicsLint as rustc_mir_transform[e7af90bdb15a3f20]::pass_manager::MirLint>::run_lint
  26:     0x7e3cb880b6f3 - rustc_mir_transform[e7af90bdb15a3f20]::run_analysis_to_runtime_passes
  27:     0x7e3cb8c28174 - rustc_mir_transform[e7af90bdb15a3f20]::mir_drops_elaborated_and_const_checked
  28:     0x7e3cb8c27da5 - rustc_query_impl[283282ac12660651]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[283282ac12660651]::query_impl::mir_drops_elaborated_and_const_checked::dynamic_query::{closure#2}::{closure#0}, rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 8usize]>>
  29:     0x7e3cb8c2bcd9 - rustc_query_system[57efd1c10fae1b2]::query::plumbing::try_execute_query::<rustc_query_impl[283282ac12660651]::DynamicConfig<rustc_data_structures[ff6b6eb237e26604]::vec_cache::VecCache<rustc_span[6fdbe82b95f770dc]::def_id::LocalDefId, rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 8usize]>, rustc_query_system[57efd1c10fae1b2]::dep_graph::graph::DepNodeIndex>, false, false, false>, rustc_query_impl[283282ac12660651]::plumbing::QueryCtxt, true>
  30:     0x7e3cb8c24dae - rustc_query_impl[283282ac12660651]::query_impl::mir_drops_elaborated_and_const_checked::get_query_incr::__rust_end_short_backtrace
  31:     0x7e3cb8c248f3 - <rustc_middle[d099a8b084c78b18]::hir::map::Map>::par_body_owners::<rustc_interface[5facaafd3cd44e6f]::passes::run_required_analyses::{closure#3}::{closure#0}>::{closure#0}
  32:     0x7e3cb8c21df4 - rustc_interface[5facaafd3cd44e6f]::passes::run_required_analyses
  33:     0x7e3cb976ca9e - rustc_interface[5facaafd3cd44e6f]::passes::analysis
  34:     0x7e3cb976ca6f - rustc_query_impl[283282ac12660651]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[283282ac12660651]::query_impl::analysis::dynamic_query::{closure#2}::{closure#0}, rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 0usize]>>
  35:     0x7e3cb97683cf - rustc_query_system[57efd1c10fae1b2]::query::plumbing::try_execute_query::<rustc_query_impl[283282ac12660651]::DynamicConfig<rustc_query_system[57efd1c10fae1b2]::query::caches::SingleCache<rustc_middle[d099a8b084c78b18]::query::erase::Erased<[u8; 0usize]>>, false, false, false>, rustc_query_impl[283282ac12660651]::plumbing::QueryCtxt, true>
  36:     0x7e3cb9767d47 - rustc_query_impl[283282ac12660651]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace
  37:     0x7e3cb9820669 - rustc_interface[5facaafd3cd44e6f]::passes::create_and_enter_global_ctxt::<core[b8d8efd06dd057cd]::option::Option<rustc_interface[5facaafd3cd44e6f]::queries::Linker>, rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}::{closure#2}>::{closure#2}::{closure#0}
  38:     0x7e3cb9813896 - rustc_interface[5facaafd3cd44e6f]::interface::run_compiler::<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}
  39:     0x7e3cb9670807 - std[4faddc71fb6fa0e5]::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_with_globals<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5facaafd3cd44e6f]::interface::run_compiler<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
  40:     0x7e3cb96704d9 - <<std[4faddc71fb6fa0e5]::thread::Builder>::spawn_unchecked_<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_with_globals<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5facaafd3cd44e6f]::interface::run_compiler<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core[b8d8efd06dd057cd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
  41:     0x7e3cb966fc6b - std::sys::pal::unix::thread::Thread::new::thread_start::h07063fc11dcd9adf
  42:     0x7e3cb389ca94 - start_thread
                               at ./nptl/pthread_create.c:447:8
  43:     0x7e3cb3929c3c - clone3
                               at ./misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:78:0
  44:                0x0 - <unknown>


rustc version: 1.86.0-nightly (9a1d156f3 2025-01-19)
platform: x86_64-unknown-linux-gnu

query stack during panic:
#0 [eval_to_allocation_raw] const-evaluating + checking `main::{constant#0}`
#1 [eval_to_const_value_raw] simplifying constant for the type system `main::{constant#0}`
#2 [mir_drops_elaborated_and_const_checked] elaborating drops for `main`
#3 [analysis] running analysis passes on this crate
end of query stack

Meta

rustc --version --verbose:

rustc 1.86.0-nightly (9a1d156f3 2025-01-19)
binary: rustc
commit-hash: 9a1d156f38c51441ee51e5a068f1d0caf4bb0f27
commit-date: 2025-01-19
host: x86_64-unknown-linux-gnu
release: 1.86.0-nightly
LLVM version: 19.1.7

Error output

Error output
thread 'rustc' panicked at /rustc/9a1d156f38c51441ee51e5a068f1d0caf4bb0f27/compiler/rustc_const_eval/src/interpret/call.rs:253:13:
assertion failed: caller_abi.eq_abi(callee_abi)
stack backtrace:
   0:     0x78aed8af951a - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h70d5098cfd90b01a
   1:     0x78aed9212da6 - core::fmt::write::h854c563aac02d08a
   2:     0x78aeda171291 - std::io::Write::write_fmt::hac4174e389a0e8e6
   3:     0x78aed8af9372 - std::sys::backtrace::BacktraceLock::print::hc6aba0d6b3a91e1f
   4:     0x78aed8afb7f2 - std::panicking::default_hook::{{closure}}::h9628a97795328020
   5:     0x78aed8afb67a - std::panicking::default_hook::h0dc7e102448ae736
   6:     0x78aed7c59eeb - std[4faddc71fb6fa0e5]::panicking::update_hook::<alloc[c55780341d73682]::boxed::Box<rustc_driver_impl[80a9ca323d3e3890]::install_ice_hook::{closure#1}>>::{closure#0}
   7:     0x78aed8afc333 - std::panicking::rust_panic_with_hook::hf47d9e178e038701
   8:     0x78aed8afbff6 - std::panicking::begin_panic_handler::{{closure}}::hd9b9f2d3dd54e86c
   9:     0x78aed8af99e9 - std::sys::backtrace::__rust_end_short_backtrace::h342bb668fc58e319
  10:     0x78aed8afbced - rust_begin_unwind
  11:     0x78aed57a8db0 - core::panicking::panic_fmt::hb3cd74fdfc019257
  12:     0x78aed6297b9c - core::panicking::panic::h92e08174b9fe42d1
  13:     0x592a4689f7ae - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<miri[d18ac4a41561b88d]::machine::MiriMachine>>::check_argument_compat
  14:     0x592a4689ec5a - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<miri[d18ac4a41561b88d]::machine::MiriMachine>>::init_stack_frame
  15:     0x592a4689c98b - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<miri[d18ac4a41561b88d]::machine::MiriMachine>>::init_fn_call
  16:     0x592a46915db4 - miri[d18ac4a41561b88d]::eval::eval_entry::{closure#0}
  17:     0x592a46911e9b - miri[d18ac4a41561b88d]::eval::eval_entry
  18:     0x592a467c4226 - <miri[e9b5d2e94aebaf6c]::MiriCompilerCalls as rustc_driver_impl[80a9ca323d3e3890]::Callbacks>::after_analysis
  19:     0x78aeda220676 - rustc_interface[5facaafd3cd44e6f]::passes::create_and_enter_global_ctxt::<core[b8d8efd06dd057cd]::option::Option<rustc_interface[5facaafd3cd44e6f]::queries::Linker>, rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}::{closure#2}>::{closure#2}::{closure#0}
  20:     0x78aeda213896 - rustc_interface[5facaafd3cd44e6f]::interface::run_compiler::<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}
  21:     0x78aeda070807 - std[4faddc71fb6fa0e5]::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_with_globals<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5facaafd3cd44e6f]::interface::run_compiler<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
  22:     0x78aeda0704d9 - <<std[4faddc71fb6fa0e5]::thread::Builder>::spawn_unchecked_<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_with_globals<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5facaafd3cd44e6f]::interface::run_compiler<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core[b8d8efd06dd057cd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
  23:     0x78aeda06fc6b - std::sys::pal::unix::thread::Thread::new::thread_start::h07063fc11dcd9adf
  24:     0x78aed429ca94 - start_thread
                               at ./nptl/pthread_create.c:447:8
  25:     0x78aed4329c3c - clone3
                               at ./misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:78:0
  26:                0x0 - <unknown>

error: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/miri/issues/new

note: please make sure that you have updated to the latest nightly

note: please attach the file at `/tmp/sadkjlhfsakdf/rustc-ice-2025-01-21T00_17_45-3693735.txt` to your bug report

note: compiler flags: --crate-type bin -C embed-bitcode=no -C debuginfo=2 -C incremental=[REDACTED]

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
end of query stack

Miri caused an ICE during evaluation. Here's the interpreter backtrace at the time of the panic:
note: the place in the program where the ICE was triggered
  --> src/main.rs:7:5
   |
7  |     panic!()
   |     ^^^^^^^^
   |
   = note: BACKTRACE:
   = note: inside `foo` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panic.rs:90:9: 90:30
note: inside `main`
  --> src/main.rs:12:5
   |
12 |     f();
   |     ^^^
   = note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5: 250:71
   = note: inside `std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/backtrace.rs:152:18: 152:21
   = note: inside closure at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:194:18: 194:75
   = note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:284:13: 284:31
   = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:587:40: 587:43
   = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:550:19: 550:88
   = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:358:14: 358:33
   = note: inside closure at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:163:24: 163:49
   = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:587:40: 587:43
   = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#0}}>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:550:19: 550:88
   = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:358:14: 358:33
   = note: inside `std::rt::lang_start_internal` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:159:5: 181:7
   = note: inside `std::rt::lang_start::<()>` at /home/zachary/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:193:5: 198:6
   = note: this note originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)

ICE file

thread 'rustc' panicked at /rustc/9a1d156f38c51441ee51e5a068f1d0caf4bb0f27/compiler/rustc_const_eval/src/interpret/call.rs:253:13:
assertion failed: caller_abi.eq_abi(callee_abi)
stack backtrace:
   0:     0x78aeda5652a5 - std::backtrace::Backtrace::create::h8985a2f6ef2eb84f
   1:     0x78aed8ae39f5 - std::backtrace::Backtrace::force_capture::h9a611efb2a942dc9
   2:     0x78aed7c5a4e0 - std[4faddc71fb6fa0e5]::panicking::update_hook::<alloc[c55780341d73682]::boxed::Box<rustc_driver_impl[80a9ca323d3e3890]::install_ice_hook::{closure#1}>>::{closure#0}
   3:     0x78aed8afc333 - std::panicking::rust_panic_with_hook::hf47d9e178e038701
   4:     0x78aed8afbff6 - std::panicking::begin_panic_handler::{{closure}}::hd9b9f2d3dd54e86c
   5:     0x78aed8af99e9 - std::sys::backtrace::__rust_end_short_backtrace::h342bb668fc58e319
   6:     0x78aed8afbced - rust_begin_unwind
   7:     0x78aed57a8db0 - core::panicking::panic_fmt::hb3cd74fdfc019257
   8:     0x78aed6297b9c - core::panicking::panic::h92e08174b9fe42d1
   9:     0x592a4689f7ae - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<miri[d18ac4a41561b88d]::machine::MiriMachine>>::check_argument_compat
  10:     0x592a4689ec5a - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<miri[d18ac4a41561b88d]::machine::MiriMachine>>::init_stack_frame
  11:     0x592a4689c98b - <rustc_const_eval[e3d2a21e14ef9d90]::interpret::eval_context::InterpCx<miri[d18ac4a41561b88d]::machine::MiriMachine>>::init_fn_call
  12:     0x592a46915db4 - miri[d18ac4a41561b88d]::eval::eval_entry::{closure#0}
  13:     0x592a46911e9b - miri[d18ac4a41561b88d]::eval::eval_entry
  14:     0x592a467c4226 - <miri[e9b5d2e94aebaf6c]::MiriCompilerCalls as rustc_driver_impl[80a9ca323d3e3890]::Callbacks>::after_analysis
  15:     0x78aeda220676 - rustc_interface[5facaafd3cd44e6f]::passes::create_and_enter_global_ctxt::<core[b8d8efd06dd057cd]::option::Option<rustc_interface[5facaafd3cd44e6f]::queries::Linker>, rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}::{closure#2}>::{closure#2}::{closure#0}
  16:     0x78aeda213896 - rustc_interface[5facaafd3cd44e6f]::interface::run_compiler::<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}
  17:     0x78aeda070807 - std[4faddc71fb6fa0e5]::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_with_globals<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5facaafd3cd44e6f]::interface::run_compiler<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
  18:     0x78aeda0704d9 - <<std[4faddc71fb6fa0e5]::thread::Builder>::spawn_unchecked_<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_with_globals<rustc_interface[5facaafd3cd44e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5facaafd3cd44e6f]::interface::run_compiler<(), rustc_driver_impl[80a9ca323d3e3890]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core[b8d8efd06dd057cd]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
  19:     0x78aeda06fc6b - std::sys::pal::unix::thread::Thread::new::thread_start::h07063fc11dcd9adf
  20:     0x78aed429ca94 - start_thread
                               at ./nptl/pthread_create.c:447:8
  21:     0x78aed4329c3c - clone3
                               at ./misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:78:0
  22:                0x0 - <unknown>


rustc version: 1.86.0-nightly (9a1d156f3 2025-01-19)
platform: x86_64-unknown-linux-gnu

query stack during panic:
end of query stack

@rustbot label +A-miri +A-ABI


This shouldn't ICE regardless, but whether there is a miscompilation depends on if the original code is sound:

CC rust-lang/unsafe-code-guidelines#485

Possible Miscompilation

Does #[repr(transparent)]s ABI-compatility guarantee apply in the prescence of uninhabited 1-ZST fields?

A #[repr(transparent)] wrapper that contains an uninhabited 1-ZST field gets Uninhabited ABI IIUC, which may contradict the guarantees about #[repr(transparent)] wrappers being ABI-compatible.

Consider Foo from above:

type Field = u8; // any non-1ZST probably
#[repr(transparent)]
struct Foo {
  _zst: std::convert::Infallible,
  _field: Field,
}

If #[repr(transparent)]'s ABI-compatility guarantees do apply, then the above code should be sound:

  1. If a function returns Foo, it must diverge (e.g. by panicking).
  2. If Foo is ABI-compatible with Field, then it should be sound to transmute a function pointer to a diverging fn() -> Foo into a fn() -> Field that also diverges.
rustc_layout(debug)

Using #![feature(rustc_attrs)] and #[rustc_layout(debug)] we see that the ABI it has is

error: layout_of(Foo) = Layout {
          // snip
           abi: Uninhabited,
          // snip
       }

whereas Field has

error: layout_of(u8) = Layout {
           // snip
           abi: Scalar(
               Initialized {
                   value: Int(
                       I8,
                       false,
                   ),
                   valid_range: 0..=255,
               },
           ),
           // snip
        }

Possible Miscompilation

Assuming this is supposed to be sound, then there is an observable miscompilation here too. Where Field is returned by invisible reference, fn(u32) -> Foo does not return Foo by invisible reference, so transmuting fn(u32) -> Foo into fn(u32) -> Field will pass a different number of arguments.

Specifically on x86_64-unknown-linux-gnu: If Field is returned on the stack, then fn(..) -> Foo does not reserve stack space or pass a hidden reference parameter, but fn(..) -> Field does. This can be made into an observable miscompilation if the function takes parameters: (playground link, IIUC: the invisible reference is being passed, but the callee isn't expecting it, so it thinks it's the first "real" parameter instead (caller: ret by-ref in rdi, x in rsi; callee: ret uninhabited, x in rdi)).

Footnotes

  1. see "Possible Miscompilation" section

@zachs18 zachs18 added C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 21, 2025
@rustbot rustbot added needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. A-ABI Area: Concerning the application binary interface (ABI) A-miri Area: The miri tool labels Jan 21, 2025
@ia0

This comment has been minimized.

@RalfJung
Copy link
Member

That would be a breaking change though since we currently accept code like this on stable:

enum Void {}

#[rept(transparent)]
struct Wrap<T>(Void, T);

@rust-lang/lang turns out accepting this code is incoherent; we cannot make this a transparent wrapper around T as Wrap<T> and T can behave differently when used as return type for a function. Would you be open to making this a hard error (likely with a transition period)?

Cc @rust-lang/opsem

@RalfJung RalfJung changed the title Miri ICE/possible miscompilation with diverging function returning repr(transparent) wrapper with uninhabited ZST, transmuted to function pointer returning wrapped field. repr(transparent) wrapper with uninhabited ZST has different return ABI than wrapped field. Jan 23, 2025
@RalfJung RalfJung added the I-lang-nominated Nominated for discussion during a lang team meeting. label Jan 23, 2025
@hanna-kruppe
Copy link
Contributor

I’m not sure it’s incoherent from a language perspective. Clearly it clashes with the current lowering chosen by the compiler, but this may just be a compiler bug.

There’s no problem when the 1-ZST field is inhabited from the compiler’s perspective, even if it has a custom safety invariant that makes it effectively impossible to construct, right? It’s just that the compiler currently applies the “return type is known to be uninhabited -> function can’t return at all” reasoning to functions where this contradicts our general function ABI compatibility rules. Similarly, if there was a target where NonZeroU32 could be passed in a different set of registers than regular u32, it would also be incorrect for rustc to pass NonZeroU32 arguments and results in those registers because someone might transmute fn(u32) -> NonZeroU32 to fn(NonZeroU32) -> u32 and call it and that would be fine according to https://doc.rust-lang.org/std/primitive.fn.html#abi-compatibility — even sound w.r.t. the safety invariant of NonZeroU32.

Changing this would be a slight loss of optimization power in theory but it doesn’t seem so bad since any call site that calls the function as fn() -> Foo is still assured that the call won’t return, even if it may need to reserve stack space that could otherwise be omitted. But this is already the case for functions returning e.g., (String, !, bool) since that’s not a ZST either - so it’s not specific to repr(transparent) or ABI compatibility rules.

@ia0

This comment has been minimized.

@hanna-kruppe
Copy link
Contributor

hanna-kruppe commented Jan 23, 2025

It's the fault of crate_bar for trying to construct a Foo value via transmute without knowing the full safety and validity invariants of Foo (I'm pretty sure a transmute in the other direction is always sound, it should be equivalent to just reading the public field). This is not only about whether the compiler considers something uninhabited. For example, suppose the private field in the newtype wrapper is an inhabited ZST that serves as witness of std::is_*_feature_detected!("some_specific_target_feature"), with a safe constructor that checks this condition. Then crate_foo may use existence of this witness to justify invoking std::arch intrinsics that are UB to call if the corresponding target_feature is not actually available. In this case crate_bar's transmute is unsound for exactly the same reason, but without any language-level invariants being involved.

(This is not a fictional example, I've written such code before except that I did not yet put the witness ZST in a field of a transparent wrapper.)

@RalfJung
Copy link
Member

It’s just that the compiler currently applies the “return type is known to be uninhabited -> function can’t return at all” reasoning to functions where this contradicts our general function ABI compatibility rules.

I am not sure what alternative fix you are suggesting though. We would have to entirely remove BackendRepr::Uninhabited, or at least stop using it for the ABI.

To me this seems like a clear oversight -- we intended to only allow fields that are irrelevant to the language (ignoring safety invariants, the user is responsible for that), but forgot about uninhabited types.

@ia0

This comment has been minimized.

@hanna-kruppe
Copy link
Contributor

I don't see any repr(transparent) in your example. I wanted to check if the repr(transparent) is part of the public API or not.

As I said, that specific code doesn't interact with repr(transparent) (yet?), I linked it to illustrate the specific invariant I chose as example. But it's easy to imagine similar code where the Avx2 type is part of a #[repr(transparent)] struct U32x8(Avx2, __m256i) wrapper that implements core::ops::Add etc. and documents that it's a transparent wrapper. I just didn't have much need for that in the code I wrote because there's not enough code operating on such vectors to pay off the boilerplate of a wrapper type.

That's the concern in my opinion. Are you allowed to transmute from the inner type to the outer type of a repr(transparent) if the only thing you know is that the outer type is indeed a repr(transparent) of the inner type?

repr(really-transparent) gives you both the repr guarantee and the permission to transmute between inner and outer

Note that transparent wrappers have always been able to add extra safety invariants to the non-ZST field (e.g., NonZero* and NonNull<T> types are transparent). So even ignoring the 1-ZST fields, it's never been true in general that you can safely transmute from T to WrapsT without considering the specifics of WrapsT.

@ia0

This comment has been minimized.

@zachs18
Copy link
Contributor Author

zachs18 commented Jan 23, 2025

It’s just that the compiler currently applies the “return type is known to be uninhabited -> function can’t return at all” reasoning to functions where this contradicts our general function ABI compatibility rules.

I am not sure what alternative fix you are suggesting though. We would have to entirely remove BackendRepr::Uninhabited, or at least stop using it for the ABI.

I don't know the relevant compiler internals, but would it be possible to only stop using BackendRepr::Uninhabited for #[repr(transparent)] types? e.g. #[repr(Rust)] struct Foo(Infallible, u32); could still have Uninhabited ABI.

@hanna-kruppe
Copy link
Contributor

@RalfJung

I am not sure what alternative fix you are suggesting though. We would have to entirely remove BackendRepr::Uninhabited, or at least stop using it for the ABI.

Yes, something like that. Specifically, I think it would be sufficient if functions that return a transparent wrapper around an inhabited type were compiled as if their return type was inhabited, even if the transparent wrapper has uninhabited 1-ZST types. I realize that such a fine distinction is difficult to fit into rustc's inner workings, but e.g. I don't think there's any need to change the ABI of e.g. fn() -> (u32, !). Unless we start guaranteeing something like "tuples where all but one elements are 1-ZST are ABI compatible with the sole non-1-ZST field," there's no valid way to transmute fn() -> (u32, !) into a function with an inhabited return type.

To me this seems like a clear oversight -- we intended to only allow fields that are irrelevant to the language (ignoring safety invariants, the user is responsible for that), but forgot about uninhabited types.

Rust has historically missed several nuances w.r.t. repr(transparent) (see also: MaybeUninit not preserving all bytes) and uninhabited 1-ZSTs probably would have been excluded if people had thought about this corner case. But I don't think it's "incoherent enough" that a breaking change is necessary. Breaking it may still be fine if it has ~zero practical impact, but it's not the only option.

@hanna-kruppe
Copy link
Contributor

@ia0

Same as above. The repr(transparent) is not part of the public API, so you can't transmute based on that information in the first place. So I wouldn't even say that NonZero is transparent, because that's an implementation detail.

It's possible to draw a distinction between repr(transparent) annotations that are intended to be public API and those that are an internal implementation detail, bit NonZero's is pretty public. rustdoc doesn't show the attribute, that's due to a heuristic based on privacy of the non-ZST field without any way to opt into declaring it public without making the field public (which NonZero probably doesn't want, e.g., to be forward compatible with pattern types). The documentation does not literally say "this is a repr(transparent) wrapper" in prose, but the standard library still guarantees every property that repr(transparent) implies:

So it's as basically close to making that part of its public ABI as you can get within the current limitations of rustdoc. Transmuting from it to the underlying integer type is allowed and the other direction is also allowed with the exception of 0.

@hanna-kruppe
Copy link
Contributor

Also, the aforementioned rustdoc heuristic means that a type like I mentioned previously:

But it's easy to imagine similar code where the Avx2 type is part of a #[repr(transparent)] struct U32x8(Avx2, __m256i) wrapper that implements core::ops::Add etc. and documents that it's a transparent wrapper.

indeed shows the attribute in its documentation:

use core::arch::x86_64::__m256i;

struct HasAvx2 {
    _feature_detected: (),
}

#[repr(transparent)]
pub struct U32x8(pub __m256i, HasAvx2);

Image

@ia0
Copy link
Contributor

ia0 commented Jan 23, 2025

So it's as basically close to making that part of its public ABI as you can get within the current limitations of rustdoc.

Yes, I consider this part of the public API. It's just there by definition rather than by name, which removes any possible ambiguity on the interpretation of the name (i.e. it's just about layout and ABI, and not about the set of valid representations).

Thanks for all the clarifications! From my point of view, I got convinced that the current definition of repr(transparent), even if unintuitive from its name (only the layout and ABI is transparent, not the set of valid representations), is actually expressive enough as it is for all intents and purposes. If one needs to document that a type is repr(really-transparent) they can derive bytemuck::TransparentWrapper which will check that the ignored fields are inhabited through the Zeroable unsafe trait safety documentation.

@RalfJung
Copy link
Member

I don't know the relevant compiler internals, but would it be possible to only stop using BackendRepr::Uninhabited for #[repr(transparent)] types? e.g. #[repr(Rust)] struct Foo(Infallible, u32); could still have Uninhabited ABI.

Infallible and ! itself could not use the Uninhabited ABI any more so at that point it seems pointless to keep the ABI around at all.

Specifically, I think it would be sufficient if functions that return a transparent wrapper around an inhabited type were compiled as if their return type was inhabited,

We need to compile fn() -> ! and fn() -> Wrap<!> the same, so this would affect all functions returning !, not just the ones returning wrappers around !.


That said, I don't actually know which effect ! has on the ABI. If it just affects the noreturn attribute then I think ! and () are actually compatible as return types. @bjorn3 do you know what we do with BackendRepr::Uninhabited in terms of ABI?

@hanna-kruppe
Copy link
Contributor

hanna-kruppe commented Jan 23, 2025

We need to compile fn() -> ! and fn() -> Wrap<!> the same, so this would affect all functions returning !, not just the ones returning wrappers around !.

Ah, because (edit: this step is nonsense, but I’m glad that whatever my thought process was took me to the following)

Because "Any two types with size 0 and alignment 1 are ABI-compatible." you can at least reproduce the miri crash without any transparent wrapper:

enum Void {}
fn foo() -> Void {
  panic!()
}
fn main() {
  let f: fn() -> Void = foo;
  let f: fn() = unsafe { std::mem::transmute(f) };
  f();
}

This is less likely to lead to an actual miscompilation because both return types being ZST should erase any differences in the generated machine code. But I feel like it points towards the root of the problem being ABI compatibility vs. exploiting uninhabited return types. Transparent wrappers are just an easy way to exercise it with the relatively small set of current ABI compatibility guarantees.

@bjorn3
Copy link
Member

bjorn3 commented Jan 23, 2025

do you know what we do with BackendRepr::Uninhabited in terms of ABI?

We treat it mostly as a ZST I think, though if you return an uninhabited type, the return terminator gets replaced by unreachable:

if self.fn_abi.ret.layout.is_uninhabited() {
// Functions with uninhabited return values are marked `noreturn`,
// so we should make sure that we never actually do.
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
// if that turns out to be helpful.
bx.abort();
// `abort` does not terminate the block, so we still need to generate
// an `unreachable` terminator after it.
bx.unreachable();
return;
}
And if you accept an uninhabited type as argument, cg_clif replaces the function body with a trap:
let arg_uninhabited = fx
.mir
.args_iter()
.any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).is_uninhabited());
if arg_uninhabited {
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
return;
}
(cg_clif has been doing this ever since 958c585)

@jieyouxu jieyouxu added A-repr Area: the `#[repr(stuff)]` attribute T-lang Relevant to the language team, which will review and decide on the PR/issue. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Jan 24, 2025
@RalfJung RalfJung removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Jan 25, 2025
@RalfJung
Copy link
Member

Because "Any two types with size 0 and alignment 1 are ABI-compatible." you can at least reproduce the miri crash without any transparent wrapper:

Ah, good point.

The Miri ICE can probably be fixed by adjusting this check, but it doesn't seem right to permit Uninhabited to match all other BackendRepr there... unless maybe we can/should enforce that all BackendRepr::Uninhabited are set to PassMode::Ignore and therefore trivially compatible with each other and with ZST?

@CAD97
Copy link
Contributor

CAD97 commented Jan 25, 2025

Vibe-wise it feels like -> ! should be compatible with any return value (it doesn't return, after all), but clearly that isn't the case at the ABI level. After accounting for that return by out parameter exists, my vibes would suggest that inhabitedness shouldn't impact ABI at all, and should be passed as it otherwise would be; as an argument, ABI doesn't matter anyway (the function can't be called), and as a return value, predictability is better than saving that small bit of stack space1.

As for #[repr(transparent)], personally I'd initially expect one of exclusively Repr::Uninhabited to be Repr::Uninhabited, ignoring specifically PhantomData (or #[repr(transparent)] of solely PhantomData), but if any other fields are present, to have an inhabited ABI.

Footnotes

  1. A similar argument as to &mut MaybeUninit<T> can be made here, as that's roughly what an outparam is, especially in the face of some forms of (even partial) (N)RVO for in-place construction2.

  2. IIRC we're ordering our semantics to allow the let place in let place = f(); to alias the fn's locals (thus including return value). Although it's not possible to do so for place = f(); since that place exists before the function call in that case, unless we specifically allow for it, which doesn't really seem worth it…

@RalfJung
Copy link
Member

my vibes would suggest that inhabitedness shouldn't impact ABI at all, and should be passed as it otherwise would be

That's not even well-defined though with the current rustc architecture; the BackendRepr is usually used to determine the ABI but, well, that one is BackendRepr::Uninhabited so we cannot distinguish Scalar and Aggregate...

@zachs18
Copy link
Contributor Author

zachs18 commented Jan 26, 2025

I have two branches for possible resolutions of this isssue:

  1. Make #[repr(transparent)] wrappers still be ABI-compatible even if there's an uninhabited 1-ZST to fix the miscompilation, by removing BackendRepr::Uninhabited, (and instead having an uninhabited: bool field on LayoutData so inhabitedness can still be queried for LayoutData): master...zachs18:rust:backend-repr-remove-uninhabited
  2. Emit a future-compatibility warning for #[repr(transparent)] wrappers with uninhabited 1-ZST fields, for them to be disallowed later: master...zachs18:rust:repr-transparent-disallow-uninhabited-zsts

Personally, I would prefer option 1, but IIUC this needs a T-lang decision?

@hanna-kruppe
Copy link
Contributor

Since both branches target repr(transparent) wrapper specifically, neither of them would fix the miri ICE due to the claimed ABI compatibility of e.g. () and !, right?

@zachs18
Copy link
Contributor Author

zachs18 commented Jan 26, 2025

The first doesn't specifically target #[repr(transparent)], it completely removes BackendRepr::Uninhabited, so would affect all uninhabited types' ABIs, not just #[repr(transparent)] ones12.

It does appear to fix the ICE from this snippet as well, which makes sense, it makes LayoutData::eq_abi not care about inhabitedness.

`#[rustc_layout(debug)]`s of `enum Void {}` and unit under option 1
error: layout_of(()) = Layout {
           size: Size(0 bytes),
           align: AbiAndPrefAlign {
               abi: Align(1 bytes),
               pref: Align(8 bytes),
           },
           abi: Memory {
               sized: true,
           },
           fields: Arbitrary {
               offsets: [],
               memory_index: [],
           },
           largest_niche: None,
           uninhabited: false,
           variants: Single {
               index: 0,
           },
           max_repr_align: None,
           unadjusted_abi_align: Align(1 bytes),
           randomization_seed: 0,
       }
 --> src/main.rs:4:1
  |
4 | pub type A = ();
  | ^^^^^^^^^^

error: layout_of(Void) = Layout {
           size: Size(0 bytes),
           align: AbiAndPrefAlign {
               abi: Align(1 bytes),
               pref: Align(1 bytes),
           },
           abi: Memory {
               sized: true,
           },
           fields: Primitive,
           largest_niche: None,
           uninhabited: true,
           variants: Empty,
           max_repr_align: None,
           unadjusted_abi_align: Align(1 bytes),
           randomization_seed: 0,
       }
 --> src/main.rs:6:1
  |
6 | enum Void {}
  | ^^^^^^^^^
$ cargo +dev-compiler-2-stage2 miri run
Preparing a sysroot for Miri (target: x86_64-unknown-linux-gnu)... done
   Compiling miri-thing v0.1.0 (/tmp/miri-thing)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s
     Running `/home/zachary/Programming/rust/rust-worktree/rust-compiler-2/build/x86_64-unknown-linux-gnu/stage2/bin/cargo-miri runner /home/zachary/opt_mount/zachary/cargo-target/miri/x86_64-unknown-linux-gnu/debug/miri-thing`

thread 'main' panicked at src/main.rs:3:3:
explicit panic
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

Footnotes

  1. though as has been mentioned, argument ABI of uninhabited types is mostly unimportant, so this only really changes return ABI

  2. practically there will be no difference on most targets for most uninhabited types that are small enough to be passed in registers now anyway

@RalfJung
Copy link
Member

Option 1 only changes compiler-internal implementation details, doesn't it? So an MCP should be sufficient for that.

I do like that option. :)

Zalathar added a commit to Zalathar/rust that referenced this issue Feb 18, 2025
…bited, r=workingjubilee

Do not ignore uninhabited types for function-call ABI purposes. (Remove BackendRepr::Uninhabited)

Accepted MCP: rust-lang/compiler-team#832

Fixes rust-lang#135802

Do not consider the inhabitedness of a type for function call ABI purposes.

* Remove the [`rustc_abi::BackendRepr::Uninhabited`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/enum.BackendRepr.html) variant
  * Instead calculate the `BackendRepr` of uninhabited types "normally" (as though they were not uninhabited "at the top level", but still considering inhabitedness of variants to determine enum layout, etc)
* Add an `uninhabited: bool` field to [`rustc_abi::LayoutData`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/struct.LayoutData.html) so inhabitedness of a `LayoutData` can still be queried when necessary (e.g. when determining if an enum variant needs a tag value allocated to it).

This should not affect type layouts (size/align/field offset); this should only affect function call ABI, and only of uninhabited types.

cc `@RalfJung`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 18, 2025
…bited, r=workingjubilee

Do not ignore uninhabited types for function-call ABI purposes. (Remove BackendRepr::Uninhabited)

Accepted MCP: rust-lang/compiler-team#832

Fixes rust-lang#135802

Do not consider the inhabitedness of a type for function call ABI purposes.

* Remove the [`rustc_abi::BackendRepr::Uninhabited`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/enum.BackendRepr.html) variant
  * Instead calculate the `BackendRepr` of uninhabited types "normally" (as though they were not uninhabited "at the top level", but still considering inhabitedness of variants to determine enum layout, etc)
* Add an `uninhabited: bool` field to [`rustc_abi::LayoutData`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/struct.LayoutData.html) so inhabitedness of a `LayoutData` can still be queried when necessary (e.g. when determining if an enum variant needs a tag value allocated to it).

This should not affect type layouts (size/align/field offset); this should only affect function call ABI, and only of uninhabited types.

cc ``@RalfJung``
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 18, 2025
…bited, r=workingjubilee

Do not ignore uninhabited types for function-call ABI purposes. (Remove BackendRepr::Uninhabited)

Accepted MCP: rust-lang/compiler-team#832

Fixes rust-lang#135802

Do not consider the inhabitedness of a type for function call ABI purposes.

* Remove the [`rustc_abi::BackendRepr::Uninhabited`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/enum.BackendRepr.html) variant
  * Instead calculate the `BackendRepr` of uninhabited types "normally" (as though they were not uninhabited "at the top level", but still considering inhabitedness of variants to determine enum layout, etc)
* Add an `uninhabited: bool` field to [`rustc_abi::LayoutData`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/struct.LayoutData.html) so inhabitedness of a `LayoutData` can still be queried when necessary (e.g. when determining if an enum variant needs a tag value allocated to it).

This should not affect type layouts (size/align/field offset); this should only affect function call ABI, and only of uninhabited types.

cc `@RalfJung`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 18, 2025
…bited, r=workingjubilee

Do not ignore uninhabited types for function-call ABI purposes. (Remove BackendRepr::Uninhabited)

Accepted MCP: rust-lang/compiler-team#832

Fixes rust-lang#135802

Do not consider the inhabitedness of a type for function call ABI purposes.

* Remove the [`rustc_abi::BackendRepr::Uninhabited`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/enum.BackendRepr.html) variant
  * Instead calculate the `BackendRepr` of uninhabited types "normally" (as though they were not uninhabited "at the top level", but still considering inhabitedness of variants to determine enum layout, etc)
* Add an `uninhabited: bool` field to [`rustc_abi::LayoutData`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/struct.LayoutData.html) so inhabitedness of a `LayoutData` can still be queried when necessary (e.g. when determining if an enum variant needs a tag value allocated to it).

This should not affect type layouts (size/align/field offset); this should only affect function call ABI, and only of uninhabited types.

cc ``@RalfJung``
bors added a commit to rust-lang-ci/rust that referenced this issue Feb 19, 2025
…ted, r=<try>

Do not ignore uninhabited types for function-call ABI purposes. (Remove BackendRepr::Uninhabited)

Accepted MCP: rust-lang/compiler-team#832

Fixes rust-lang#135802

Do not consider the inhabitedness of a type for function call ABI purposes.

* Remove the [`rustc_abi::BackendRepr::Uninhabited`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/enum.BackendRepr.html) variant
  * Instead calculate the `BackendRepr` of uninhabited types "normally" (as though they were not uninhabited "at the top level", but still considering inhabitedness of variants to determine enum layout, etc)
* Add an `uninhabited: bool` field to [`rustc_abi::LayoutData`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/struct.LayoutData.html) so inhabitedness of a `LayoutData` can still be queried when necessary (e.g. when determining if an enum variant needs a tag value allocated to it).

This should not affect type layouts (size/align/field offset); this should only affect function call ABI, and only of uninhabited types.

cc `@RalfJung`

try-job: x86_64-gnu-nopt
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Feb 20, 2025
…bited, r=workingjubilee

Do not ignore uninhabited types for function-call ABI purposes. (Remove BackendRepr::Uninhabited)

Accepted MCP: rust-lang/compiler-team#832

Fixes rust-lang#135802

Do not consider the inhabitedness of a type for function call ABI purposes.

* Remove the [`rustc_abi::BackendRepr::Uninhabited`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/enum.BackendRepr.html) variant
  * Instead calculate the `BackendRepr` of uninhabited types "normally" (as though they were not uninhabited "at the top level", but still considering inhabitedness of variants to determine enum layout, etc)
* Add an `uninhabited: bool` field to [`rustc_abi::LayoutData`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/struct.LayoutData.html) so inhabitedness of a `LayoutData` can still be queried when necessary (e.g. when determining if an enum variant needs a tag value allocated to it).

This should not affect type layouts (size/align/field offset); this should only affect function call ABI, and only of uninhabited types.

cc `@RalfJung`
@bors bors closed this as completed in 8c9e374 Feb 21, 2025
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Feb 21, 2025
Rollup merge of rust-lang#136985 - zachs18:backend-repr-remove-uninhabited, r=workingjubilee

Do not ignore uninhabited types for function-call ABI purposes. (Remove BackendRepr::Uninhabited)

Accepted MCP: rust-lang/compiler-team#832

Fixes rust-lang#135802

Do not consider the inhabitedness of a type for function call ABI purposes.

* Remove the [`rustc_abi::BackendRepr::Uninhabited`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/enum.BackendRepr.html) variant
  * Instead calculate the `BackendRepr` of uninhabited types "normally" (as though they were not uninhabited "at the top level", but still considering inhabitedness of variants to determine enum layout, etc)
* Add an `uninhabited: bool` field to [`rustc_abi::LayoutData`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_abi/struct.LayoutData.html) so inhabitedness of a `LayoutData` can still be queried when necessary (e.g. when determining if an enum variant needs a tag value allocated to it).

This should not affect type layouts (size/align/field offset); this should only affect function call ABI, and only of uninhabited types.

cc ``@RalfJung``
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ABI Area: Concerning the application binary interface (ABI) A-miri Area: The miri tool A-repr Area: the `#[repr(stuff)]` attribute C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
8 participants