Skip to content

Commit a3711e5

Browse files
committed
Don't infer attributes of virtual calls based on the function body
1 parent 28d3fef commit a3711e5

File tree

5 files changed

+51
-50
lines changed

5 files changed

+51
-50
lines changed

compiler/rustc_middle/src/ty/instance.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ pub enum InstanceKind<'tcx> {
111111

112112
/// Dynamic dispatch to `<dyn Trait as Trait>::fn`.
113113
///
114-
/// This `InstanceKind` does not have callable MIR. Calls to `Virtual` instances must be
115-
/// codegen'd as virtual calls through the vtable.
114+
/// This `InstanceKind` may have a callable MIR as the default implementation.
115+
/// Calls to `Virtual` instances must be codegen'd as virtual calls through the vtable.
116+
/// *This means we might not know exactly what is being called.*
116117
///
117118
/// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more
118119
/// details on that).

compiler/rustc_ty_utils/src/abi.rs

+28-24
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,12 @@ fn fn_abi_of_fn_ptr<'tcx>(
309309
query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
310310
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
311311
let ty::PseudoCanonicalInput { typing_env, value: (sig, extra_args) } = query;
312-
313-
let cx = LayoutCx::new(tcx, typing_env);
314312
fn_abi_new_uncached(
315-
&cx,
313+
tcx,
314+
&LayoutCx::new(tcx, typing_env),
316315
tcx.instantiate_bound_regions_with_erased(sig),
317316
extra_args,
318317
None,
319-
None,
320-
false,
321318
)
322319
}
323320

@@ -326,19 +323,12 @@ fn fn_abi_of_instance<'tcx>(
326323
query: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
327324
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
328325
let ty::PseudoCanonicalInput { typing_env, value: (instance, extra_args) } = query;
329-
330-
let sig = fn_sig_for_fn_abi(tcx, instance, typing_env);
331-
332-
let caller_location =
333-
instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty());
334-
335326
fn_abi_new_uncached(
327+
tcx,
336328
&LayoutCx::new(tcx, typing_env),
337-
sig,
329+
fn_sig_for_fn_abi(tcx, instance, typing_env),
338330
extra_args,
339-
caller_location,
340-
Some(instance.def_id()),
341-
matches!(instance.def, ty::InstanceKind::Virtual(..)),
331+
Some(instance),
342332
)
343333
}
344334

@@ -547,18 +537,24 @@ fn fn_abi_sanity_check<'tcx>(
547537
fn_arg_sanity_check(cx, fn_abi, spec_abi, &fn_abi.ret);
548538
}
549539

550-
// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
551-
// arguments of this method, into a separate `struct`.
552-
#[tracing::instrument(level = "debug", skip(cx, caller_location, fn_def_id, force_thin_self_ptr))]
540+
#[tracing::instrument(level = "debug", skip(tcx, cx, instance))]
553541
fn fn_abi_new_uncached<'tcx>(
542+
tcx: TyCtxt<'tcx>,
554543
cx: &LayoutCx<'tcx>,
555544
sig: ty::FnSig<'tcx>,
556545
extra_args: &[Ty<'tcx>],
557-
caller_location: Option<Ty<'tcx>>,
558-
fn_def_id: Option<DefId>,
559-
// FIXME(eddyb) replace this with something typed, like an `enum`.
560-
force_thin_self_ptr: bool,
546+
instance: Option<ty::Instance<'tcx>>,
561547
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
548+
// FIXME(eddyb) replace this with something typed, like an `enum`.
549+
let (caller_location, fn_def_id, is_virtual_call) = if let Some(instance) = instance {
550+
(
551+
instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty()),
552+
Some(instance.def_id()),
553+
matches!(instance.def, ty::InstanceKind::Virtual(..)),
554+
)
555+
} else {
556+
(None, None, false)
557+
};
562558
let tcx = cx.tcx();
563559
let sig = tcx.normalize_erasing_regions(cx.typing_env, sig);
564560

@@ -603,7 +599,7 @@ fn fn_abi_new_uncached<'tcx>(
603599
});
604600

605601
let layout = cx.layout_of(ty).map_err(|err| &*tcx.arena.alloc(FnAbiError::Layout(*err)))?;
606-
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
602+
let layout = if is_virtual_call && arg_idx == Some(0) {
607603
// Don't pass the vtable, it's not an argument of the virtual fn.
608604
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
609605
// or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
@@ -648,7 +644,15 @@ fn fn_abi_new_uncached<'tcx>(
648644
conv,
649645
can_unwind: fn_can_unwind(cx.tcx(), fn_def_id, sig.abi),
650646
};
651-
fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id);
647+
fn_abi_adjust_for_abi(
648+
cx,
649+
&mut fn_abi,
650+
sig.abi,
651+
// If this is a virtual call, we cannot pass the `fn_def_id`, as it might call other
652+
// functions from vtable. Internally, `deduced_param_attrs` attempts to infer attributes by
653+
// visit the function body.
654+
fn_def_id.filter(|_| !is_virtual_call),
655+
);
652656
debug!("fn_abi_new_uncached = {:?}", fn_abi);
653657
fn_abi_sanity_check(cx, &fn_abi, sig.abi);
654658
Ok(tcx.arena.alloc(fn_abi))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//! Regression test for https://github.com/rust-lang/rust/issues/137646.
2+
//! Since we don't know the exact implementation of the virtual call,
3+
//! it might write to parameters, we can't infer the readonly attribute.
4+
//@ compile-flags: -C opt-level=3 -C no-prepopulate-passes
5+
6+
#![crate_type = "lib"]
7+
8+
pub trait Trait {
9+
fn m(&self, _: (i32, i32, i32)) {}
10+
}
11+
12+
#[no_mangle]
13+
pub fn foo(trait_: &dyn Trait) {
14+
// CHECK-LABEL: @foo(
15+
// CHECK: call void
16+
// CHECK-NOT: readonly
17+
trait_.m((1, 1, 1));
18+
}

tests/ui/virtual-call-attrs-issue-137646.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! Regression test for https://github.com/rust-lang/rust/issues/137646.
2-
//! FIXME: The parameter value at all calls to `check` should be `(1, 1, 1)`.
2+
//! The parameter value at all calls to `check` should be `(1, 1, 1)`.
33
44
//@ run-pass
5-
//@ check-run-results
65

76
use std::hint::black_box;
87

@@ -35,8 +34,7 @@ pub fn run_2(trait_: &dyn Trait) {
3534

3635
#[inline(never)]
3736
fn check(v: T) {
38-
dbg!(v);
39-
// assert_eq!(v, (1, 1, 1));
37+
assert_eq!(v, (1, 1, 1));
4038
}
4139

4240
fn main() {

tests/ui/virtual-call-attrs-issue-137646.run.stderr

-20
This file was deleted.

0 commit comments

Comments
 (0)