diff --git a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs index f2cca482ef..b591bd3f41 100644 --- a/crates/rustc_codegen_spirv/src/builder/builder_methods.rs +++ b/crates/rustc_codegen_spirv/src/builder/builder_methods.rs @@ -1267,7 +1267,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { if let SpirvValueKind::LogicalPtrCast { original_ptr, original_pointee_ty, - zombie_target_undef: _, + bitcast_result_id: _, } = ptr.kind { let offset = match pointee_kind { @@ -1533,7 +1533,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { SpirvValueKind::LogicalPtrCast { original_ptr, original_pointee_ty, - zombie_target_undef: _, + bitcast_result_id: _, } => ( original_ptr.with_type( SpirvType::Pointer { @@ -1572,11 +1572,12 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { .with_type(dest_ty) } else { // Defer the cast so that it has a chance to be avoided. + let original_ptr = val.def(self); SpirvValue { kind: SpirvValueKind::LogicalPtrCast { - original_ptr: val.def(self), + original_ptr, original_pointee_ty: val_pointee, - zombie_target_undef: self.undef(dest_ty).def(self), + bitcast_result_id: self.emit().bitcast(dest_ty, None, original_ptr).unwrap(), }, ty: dest_ty, } diff --git a/crates/rustc_codegen_spirv/src/builder_spirv.rs b/crates/rustc_codegen_spirv/src/builder_spirv.rs index 3c003c6a34..51b9901898 100644 --- a/crates/rustc_codegen_spirv/src/builder_spirv.rs +++ b/crates/rustc_codegen_spirv/src/builder_spirv.rs @@ -59,10 +59,12 @@ pub enum SpirvValueKind { /// Pointee type of `original_ptr`. original_pointee_ty: Word, - /// `OpUndef` of the right target pointer type, to attach zombies to. - // FIXME(eddyb) we should be using a real `OpBitcast` here, but we can't - // emit that on the fly during `SpirvValue::def`, due to builder locking. - zombie_target_undef: Word, + /// Result ID for the `OpBitcast` instruction representing the cast, + /// to attach zombies to. + // + // HACK(eddyb) having an `OpBitcast` only works by being DCE'd away, + // or by being replaced with a noop in `qptr::lower`. + bitcast_result_id: Word, }, } @@ -170,10 +172,10 @@ impl SpirvValue { SpirvValueKind::LogicalPtrCast { original_ptr: _, original_pointee_ty, - zombie_target_undef, + bitcast_result_id, } => { cx.zombie_with_span( - zombie_target_undef, + bitcast_result_id, span, &format!( "cannot cast between pointer types\ @@ -184,7 +186,7 @@ impl SpirvValue { ), ); - zombie_target_undef + bitcast_result_id } } } diff --git a/crates/rustc_codegen_spirv/src/linker/zombies.rs b/crates/rustc_codegen_spirv/src/linker/zombies.rs index 1e54e0213e..011e2def48 100644 --- a/crates/rustc_codegen_spirv/src/linker/zombies.rs +++ b/crates/rustc_codegen_spirv/src/linker/zombies.rs @@ -102,8 +102,9 @@ impl Zombies { // No need to zombie defs within a function: If any def within a function is zombied, then the // whole function is zombied. But, we don't have to mark the defs within a function as zombie, // because the defs can't escape the function. - // HACK(eddyb) one exception to this is function-local variables, which may - // be unused and as such cannot be allowed to always zombie the function. + // HACK(eddyb) one exception to this is function-local variables, or the + // `OpBitcast`s of pointer casts, either of which which may actually be + // unused and as such cannot be allowed to always zombie the function. for func in &module.functions { let func_id = func.def_id().unwrap(); if self.id_to_zombie_kind.contains_key(&func_id) { @@ -126,7 +127,7 @@ impl Zombies { _ => {} } - if inst.class.opcode == Op::Variable { + if [Op::Variable, Op::Bitcast].contains(&inst.class.opcode) { let result_id = inst.result_id.unwrap(); if self.id_to_zombie_kind.contains_key(&result_id) { continue; diff --git a/tests/ui/lang/core/ref/zst_member_ref_arg-broken.stderr b/tests/ui/lang/core/ref/zst_member_ref_arg-broken.stderr index bd341e6aa3..0bae7acf77 100644 --- a/tests/ui/lang/core/ref/zst_member_ref_arg-broken.stderr +++ b/tests/ui/lang/core/ref/zst_member_ref_arg-broken.stderr @@ -18,11 +18,11 @@ note: called by `main_scalar_scalar_pair_nested` | ^ error: cannot cast between pointer types - from `*struct (usize, usize) { u32, u32 }` + from `*u32` to `*struct B { }` - --> $DIR/zst_member_ref_arg-broken.rs:33:5 + --> $DIR/zst_member_ref_arg-broken.rs:23:5 | -33 | f(&s.y); +23 | f(&s.y); | ^ | note: used from within `zst_member_ref_arg_broken::main_scalar` @@ -37,11 +37,11 @@ note: called by `main_scalar` | ^ error: cannot cast between pointer types - from `*struct (usize, usize) { u32, u32 }` + from `*struct S { u32, u32 }` to `*struct B { }` - --> $DIR/zst_member_ref_arg-broken.rs:33:5 + --> $DIR/zst_member_ref_arg-broken.rs:28:5 | -33 | f(&s.y); +28 | f(&s.y); | ^ | note: used from within `zst_member_ref_arg_broken::main_scalar_pair`