1
Fork 0

Rollup merge of #122879 - maurer:callsite-instances, r=workingjubilee

CFI: Strip auto traits off Virtual calls

We already use `Instance` at declaration sites when available to glean additional information about possible abstractions of the type in use. This does the same when possible at callsites as well.

The primary purpose of this change is to allow CFI to alter how it generates type information for indirect calls through `Virtual` instances.

This is needed for the "separate machinery" version of my approach to the vtable issues (#122573), because we need to respond differently to a `Virtual` call to the same type as a non-virtual call, specifically [stripping auto traits off the receiver's `Self`](54b15b0c36) because there isn't a separate vtable for `Foo` vs `Foo + Send`.

This would also make a more general underlying mechanism that could be used by rcvalle's [proposed drop detection / encoding](edcd1e20a1) if we end up using his approach, as we could condition out on the `def_id` in the CFI code rather than requiring the generating code to explicitly note whether it was calling drop.
This commit is contained in:
Jubilee 2024-03-23 22:59:42 -07:00 committed by GitHub
commit 992aa1edb6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 155 additions and 58 deletions

View file

@ -462,27 +462,34 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let ptr_ty = cx.type_ptr();
let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
let (start_fn, start_ty, args) = if let EntryFnType::Main { sigpipe } = entry_type {
let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type
{
let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
let start_fn = cx.get_fn_addr(ty::Instance::expect_resolve(
let start_instance = ty::Instance::expect_resolve(
cx.tcx(),
ty::ParamEnv::reveal_all(),
start_def_id,
cx.tcx().mk_args(&[main_ret_ty.into()]),
));
);
let start_fn = cx.get_fn_addr(start_instance);
let i8_ty = cx.type_i8();
let arg_sigpipe = bx.const_u8(sigpipe);
let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, ptr_ty, i8_ty], isize_ty);
(start_fn, start_ty, vec![rust_main, arg_argc, arg_argv, arg_sigpipe])
(
start_fn,
start_ty,
vec![rust_main, arg_argc, arg_argv, arg_sigpipe],
Some(start_instance),
)
} else {
debug!("using user-defined start fn");
let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty);
(rust_main, start_ty, vec![arg_argc, arg_argv])
(rust_main, start_ty, vec![arg_argc, arg_argv], None)
};
let result = bx.call(start_ty, None, None, start_fn, &args, None);
let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
if cx.sess().target.os.contains("uefi") {
bx.ret(result);
} else {

View file

@ -232,6 +232,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
ret_llbb,
unwind_block,
self.funclet(fx),
instance,
);
if fx.mir[self.bb].is_cleanup {
bx.apply_attrs_to_cleanup_callsite(invokeret);
@ -247,7 +248,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
}
MergingSucc::False
} else {
let llret = bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx));
let llret =
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, llargs, self.funclet(fx), instance);
if fx.mir[self.bb].is_cleanup {
bx.apply_attrs_to_cleanup_callsite(llret);
}
@ -502,7 +504,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let ty = location.ty(self.mir, bx.tcx()).ty;
let ty = self.monomorphize(ty);
let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
let instance = drop_fn.clone();
if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
// we don't actually need to drop anything.
@ -518,7 +519,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args1 = [place.llval];
&args1[..]
};
let (drop_fn, fn_abi) =
let (drop_fn, fn_abi, drop_instance) =
match ty.kind() {
// FIXME(eddyb) perhaps move some of this logic into
// `Instance::resolve_drop_in_place`?
@ -550,6 +551,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
.get_fn(bx, vtable, ty, fn_abi),
fn_abi,
virtual_drop,
)
}
ty::Dynamic(_, _, ty::DynStar) => {
@ -592,9 +594,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
.get_fn(bx, meta.immediate(), ty, fn_abi),
fn_abi,
virtual_drop,
)
}
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
_ => (
bx.get_fn_addr(drop_fn),
bx.fn_abi_of_instance(drop_fn, ty::List::empty()),
drop_fn,
),
};
helper.do_call(
self,
@ -605,7 +612,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Some((ReturnDest::Nothing, target)),
unwind,
&[],
Some(instance),
Some(drop_instance),
mergeable_succ,
)
}
@ -1699,7 +1706,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
let fn_ty = bx.fn_decl_backend_type(fn_abi);
let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());
let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref(), None);
bx.apply_attrs_to_cleanup_callsite(llret);
}

View file

@ -709,7 +709,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
None
};
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None)
bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance))
} else {
bx.get_static(def_id)
};

View file

@ -70,7 +70,15 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// (But we are in good company, this code is duplicated plenty of times.)
let fn_ty = bx.fn_decl_backend_type(fn_abi);
bx.call(fn_ty, /* fn_attrs */ None, Some(fn_abi), llfn, &[msg.0, msg.1], None);
bx.call(
fn_ty,
/* fn_attrs */ None,
Some(fn_abi),
llfn,
&[msg.0, msg.1],
None,
None,
);
// This function does not return so we can now return whatever we want.
let size = bx.const_usize(layout.size.bytes());

View file

@ -17,7 +17,7 @@ use crate::MemFlags;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
use rustc_middle::ty::Ty;
use rustc_middle::ty::{Instance, Ty};
use rustc_session::config::OptLevel;
use rustc_span::Span;
use rustc_target::abi::call::FnAbi;
@ -82,6 +82,7 @@ pub trait BuilderMethods<'a, 'tcx>:
then: Self::BasicBlock,
catch: Self::BasicBlock,
funclet: Option<&Self::Funclet>,
instance: Option<Instance<'tcx>>,
) -> Self::Value;
fn unreachable(&mut self);
@ -389,6 +390,7 @@ pub trait BuilderMethods<'a, 'tcx>:
llfn: Self::Value,
args: &[Self::Value],
funclet: Option<&Self::Funclet>,
instance: Option<Instance<'tcx>>,
) -> Self::Value;
fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;