Increase vtable layout size
This improves LLVM's codegen by allowing vtable loads to be hoisted out of loops (as just one example).
This commit is contained in:
parent
466be510af
commit
dd9c8cc467
4 changed files with 134 additions and 74 deletions
|
@ -26,6 +26,7 @@ use rustc_middle::ty::{TypeVisitableExt, Upcast};
|
|||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::Abi;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use std::iter;
|
||||
|
@ -145,6 +146,14 @@ fn object_safety_violations_for_trait(
|
|||
violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans));
|
||||
}
|
||||
|
||||
if violations.is_empty() {
|
||||
for item in tcx.associated_items(trait_def_id).in_definition_order() {
|
||||
if let ty::AssocKind::Fn = item.kind {
|
||||
check_receiver_correct(tcx, trait_def_id, *item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
|
||||
trait_def_id, violations
|
||||
|
@ -493,59 +502,8 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
};
|
||||
errors.push(MethodViolationCode::UndispatchableReceiver(span));
|
||||
} else {
|
||||
// Do sanity check to make sure the receiver actually has the layout of a pointer.
|
||||
|
||||
use rustc_target::abi::Abi;
|
||||
|
||||
let param_env = tcx.param_env(method.def_id);
|
||||
|
||||
let abi_of_ty = |ty: Ty<'tcx>| -> Option<Abi> {
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(layout) => Some(layout.abi),
|
||||
Err(err) => {
|
||||
// #78372
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(method.def_id),
|
||||
format!("error: {err}\n while computing layout for type {ty:?}"),
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// e.g., `Rc<()>`
|
||||
let unit_receiver_ty =
|
||||
receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method.def_id);
|
||||
|
||||
match abi_of_ty(unit_receiver_ty) {
|
||||
Some(Abi::Scalar(..)) => (),
|
||||
abi => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(method.def_id),
|
||||
format!(
|
||||
"receiver when `Self = ()` should have a Scalar ABI; found {abi:?}"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let trait_object_ty = object_ty_for_trait(tcx, trait_def_id, tcx.lifetimes.re_static);
|
||||
|
||||
// e.g., `Rc<dyn Trait>`
|
||||
let trait_object_receiver =
|
||||
receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id);
|
||||
|
||||
match abi_of_ty(trait_object_receiver) {
|
||||
Some(Abi::ScalarPair(..)) => (),
|
||||
abi => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(method.def_id),
|
||||
format!(
|
||||
"receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
// We confirm that the `receiver_is_dispatchable` is accurate later,
|
||||
// see `check_receiver_correct`. It should be kept in sync with this code.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -606,6 +564,55 @@ fn virtual_call_violations_for_method<'tcx>(
|
|||
errors
|
||||
}
|
||||
|
||||
/// This code checks that `receiver_is_dispatchable` is correctly implemented.
|
||||
///
|
||||
/// This check is outlined from the object safety check to avoid cycles with
|
||||
/// layout computation, which relies on knowing whether methods are object safe.
|
||||
pub fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: ty::AssocItem) {
|
||||
if !is_vtable_safe_method(tcx, trait_def_id, method) {
|
||||
return;
|
||||
}
|
||||
|
||||
let method_def_id = method.def_id;
|
||||
let sig = tcx.fn_sig(method_def_id).instantiate_identity();
|
||||
let param_env = tcx.param_env(method_def_id);
|
||||
let receiver_ty = tcx.liberate_late_bound_regions(method_def_id, sig.input(0));
|
||||
|
||||
if receiver_ty == tcx.types.self_param {
|
||||
// Assumed OK, may change later if unsized_locals permits `self: Self` as dispatchable.
|
||||
return;
|
||||
}
|
||||
|
||||
// e.g., `Rc<()>`
|
||||
let unit_receiver_ty = receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method_def_id);
|
||||
match tcx.layout_of(param_env.and(unit_receiver_ty)).map(|l| l.abi) {
|
||||
Ok(Abi::Scalar(..)) => (),
|
||||
abi => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(method_def_id),
|
||||
format!("receiver {unit_receiver_ty:?} when `Self = ()` should have a Scalar ABI; found {abi:?}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let trait_object_ty = object_ty_for_trait(tcx, trait_def_id, tcx.lifetimes.re_static);
|
||||
|
||||
// e.g., `Rc<dyn Trait>`
|
||||
let trait_object_receiver =
|
||||
receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method_def_id);
|
||||
match tcx.layout_of(param_env.and(trait_object_receiver)).map(|l| l.abi) {
|
||||
Ok(Abi::ScalarPair(..)) => (),
|
||||
abi => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(method_def_id),
|
||||
format!(
|
||||
"receiver {trait_object_receiver:?} when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
|
||||
/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
|
||||
fn receiver_for_self_ty<'tcx>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue