Skip to content

Commit 0e43909

Browse files
authored
Rollup merge of #130734 - Luv-Ray:fix_vfe, r=lcnr
Fix: ices on virtual-function-elimination about principal trait Extract `load_vtable` function to ensure the `virtual_function_elimination` option is always checked. It's okay not to use `llvm.type.checked.load` to load the vtable if there is no principal trait. Fixes #123955 Fixes #124092
2 parents 5b72787 + 16093fa commit 0e43909

File tree

7 files changed

+61
-51
lines changed

7 files changed

+61
-51
lines changed

compiler/rustc_codegen_ssa/src/base.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use crate::back::write::{
3737
submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
3838
};
3939
use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
40+
use crate::meth::load_vtable;
4041
use crate::mir::operand::OperandValue;
4142
use crate::mir::place::PlaceRef;
4243
use crate::traits::*;
@@ -135,14 +136,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
135136

136137
if let Some(entry_idx) = vptr_entry_idx {
137138
let ptr_size = bx.data_layout().pointer_size;
138-
let ptr_align = bx.data_layout().pointer_align.abi;
139139
let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes();
140-
let gep = bx.inbounds_ptradd(old_info, bx.const_usize(vtable_byte_offset));
141-
let new_vptr = bx.load(bx.type_ptr(), gep, ptr_align);
142-
bx.nonnull_metadata(new_vptr);
143-
// VTable loads are invariant.
144-
bx.set_invariant_load(new_vptr);
145-
new_vptr
140+
load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true)
146141
} else {
147142
old_info
148143
}

compiler/rustc_codegen_ssa/src/meth.rs

+39-28
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,9 @@ impl<'a, 'tcx> VirtualIndex {
2828

2929
let llty = bx.fn_ptr_backend_type(fn_abi);
3030
let ptr_size = bx.data_layout().pointer_size;
31-
let ptr_align = bx.data_layout().pointer_align.abi;
3231
let vtable_byte_offset = self.0 * ptr_size.bytes();
3332

34-
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
35-
&& bx.cx().sess().lto() == Lto::Fat
36-
{
37-
let typeid = bx
38-
.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)))
39-
.unwrap();
40-
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
41-
func
42-
} else {
43-
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
44-
let ptr = bx.load(llty, gep, ptr_align);
45-
// VTable loads are invariant.
46-
bx.set_invariant_load(ptr);
47-
if nonnull {
48-
bx.nonnull_metadata(ptr);
49-
}
50-
ptr
51-
}
33+
load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull)
5234
}
5335

5436
pub(crate) fn get_optional_fn<Bx: BuilderMethods<'a, 'tcx>>(
@@ -75,31 +57,27 @@ impl<'a, 'tcx> VirtualIndex {
7557
self,
7658
bx: &mut Bx,
7759
llvtable: Bx::Value,
60+
ty: Ty<'tcx>,
7861
) -> Bx::Value {
7962
// Load the data pointer from the object.
8063
debug!("get_int({:?}, {:?})", llvtable, self);
8164

8265
let llty = bx.type_isize();
8366
let ptr_size = bx.data_layout().pointer_size;
84-
let ptr_align = bx.data_layout().pointer_align.abi;
8567
let vtable_byte_offset = self.0 * ptr_size.bytes();
8668

87-
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
88-
let ptr = bx.load(llty, gep, ptr_align);
89-
// VTable loads are invariant.
90-
bx.set_invariant_load(ptr);
91-
ptr
69+
load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false)
9270
}
9371
}
9472

9573
/// This takes a valid `self` receiver type and extracts the principal trait
96-
/// ref of the type.
97-
fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> {
74+
/// ref of the type. Return `None` if there is no principal trait.
75+
fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
9876
for arg in ty.peel_refs().walk() {
9977
if let GenericArgKind::Type(ty) = arg.unpack()
10078
&& let ty::Dynamic(data, _, _) = ty.kind()
10179
{
102-
return data.principal().expect("expected principal trait object");
80+
return data.principal();
10381
}
10482
}
10583

@@ -138,3 +116,36 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
138116
cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
139117
vtable
140118
}
119+
120+
/// Call this function whenever you need to load a vtable.
121+
pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
122+
bx: &mut Bx,
123+
llvtable: Bx::Value,
124+
llty: Bx::Type,
125+
vtable_byte_offset: u64,
126+
ty: Ty<'tcx>,
127+
nonnull: bool,
128+
) -> Bx::Value {
129+
let ptr_align = bx.data_layout().pointer_align.abi;
130+
131+
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
132+
&& bx.cx().sess().lto() == Lto::Fat
133+
{
134+
if let Some(trait_ref) = dyn_trait_in_self(ty) {
135+
let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap();
136+
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
137+
return func;
138+
} else if nonnull {
139+
bug!("load nonnull value from a vtable without a principal trait")
140+
}
141+
}
142+
143+
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
144+
let ptr = bx.load(llty, gep, ptr_align);
145+
// VTable loads are invariant.
146+
bx.set_invariant_load(ptr);
147+
if nonnull {
148+
bx.nonnull_metadata(ptr);
149+
}
150+
ptr
151+
}

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
126126
sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN,
127127
_ => bug!(),
128128
};
129-
let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable);
129+
let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable, callee_ty);
130130
match name {
131131
// Size is always <= isize::MAX.
132132
sym::vtable_size => {

compiler/rustc_codegen_ssa/src/size_of_val.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
2828
// Load size/align from vtable.
2929
let vtable = info.unwrap();
3030
let size = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
31-
.get_usize(bx, vtable);
31+
.get_usize(bx, vtable, t);
3232
let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
33-
.get_usize(bx, vtable);
33+
.get_usize(bx, vtable, t);
3434

3535
// Size is always <= isize::MAX.
3636
let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;

tests/crashes/123955.rs

-6
This file was deleted.

tests/crashes/124092.rs

-7
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ build-pass
2+
//@ compile-flags: -Zvirtual-function-elimination=true -Clto=true
3+
//@ only-x86_64
4+
//@ no-prefer-dynamic
5+
6+
// issue #123955
7+
pub fn test0() {
8+
_ = Box::new(()) as Box<dyn Send>;
9+
}
10+
11+
// issue #124092
12+
const X: for<'b> fn(&'b ()) = |&()| ();
13+
pub fn test1() {
14+
let _dyn_debug = Box::new(X) as Box<fn(&'static ())> as Box<dyn Send>;
15+
}
16+
17+
fn main() {}

0 commit comments

Comments
 (0)