Skip to content

Commit 6dff423

Browse files
authored
Unrolled build for rust-lang#127295
Rollup merge of rust-lang#127295 - maurer:default-impl-cfi, r=estebank CFI: Support provided methods on traits Provided methods currently don't get type erasure performed on them because they are not in an `impl` block. If we are instantiating a method that is an associated item, but *not* in an impl block, treat it as a provided method instead.
2 parents 0cd01aa + 2abdc4e commit 6dff423

File tree

2 files changed

+64
-37
lines changed

2 files changed

+64
-37
lines changed

compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs

+58-37
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use rustc_hir::LangItem;
99
use rustc_middle::bug;
1010
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
1111
use rustc_middle::ty::{
12-
self, ExistentialPredicateStableCmpExt as _, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable,
13-
TypeVisitableExt, UintTy,
12+
self, ExistentialPredicateStableCmpExt as _, Instance, InstanceKind, IntTy, List, TraitRef, Ty,
13+
TyCtxt, TypeFoldable, TypeVisitableExt, UintTy,
1414
};
15-
use rustc_span::sym;
15+
use rustc_span::{def_id::DefId, sym};
1616
use rustc_trait_selection::traits;
1717
use std::iter;
1818
use tracing::{debug, instrument};
@@ -360,41 +360,29 @@ pub fn transform_instance<'tcx>(
360360
if !options.contains(TransformTyOptions::USE_CONCRETE_SELF) {
361361
// Perform type erasure for calls on trait objects by transforming self into a trait object
362362
// of the trait that defines the method.
363-
if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
364-
&& let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
365-
{
366-
let impl_method = tcx.associated_item(instance.def_id());
367-
let method_id = impl_method
368-
.trait_item_def_id
369-
.expect("Part of a trait implementation, but not linked to the def_id?");
370-
let trait_method = tcx.associated_item(method_id);
371-
let trait_id = trait_ref.skip_binder().def_id;
372-
if traits::is_vtable_safe_method(tcx, trait_id, trait_method)
373-
&& tcx.is_object_safe(trait_id)
374-
{
375-
// Trait methods will have a Self polymorphic parameter, where the concreteized
376-
// implementatation will not. We need to walk back to the more general trait method
377-
let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
378-
instance.args,
379-
ty::ParamEnv::reveal_all(),
380-
trait_ref,
381-
);
382-
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
363+
if let Some((trait_ref, method_id, ancestor)) = implemented_method(tcx, instance) {
364+
// Trait methods will have a Self polymorphic parameter, where the concreteized
365+
// implementatation will not. We need to walk back to the more general trait method
366+
let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
367+
instance.args,
368+
ty::ParamEnv::reveal_all(),
369+
trait_ref,
370+
);
371+
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
383372

384-
// At the call site, any call to this concrete function through a vtable will be
385-
// `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
386-
// original method id, and we've recovered the trait arguments, we can make the callee
387-
// instance we're computing the alias set for match the caller instance.
388-
//
389-
// Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
390-
// If we ever *do* start encoding the vtable index, we will need to generate an alias set
391-
// based on which vtables we are putting this method into, as there will be more than one
392-
// index value when supertraits are involved.
393-
instance.def = ty::InstanceKind::Virtual(method_id, 0);
394-
let abstract_trait_args =
395-
tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
396-
instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
397-
}
373+
// At the call site, any call to this concrete function through a vtable will be
374+
// `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
375+
// original method id, and we've recovered the trait arguments, we can make the callee
376+
// instance we're computing the alias set for match the caller instance.
377+
//
378+
// Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
379+
// If we ever *do* start encoding the vtable index, we will need to generate an alias set
380+
// based on which vtables we are putting this method into, as there will be more than one
381+
// index value when supertraits are involved.
382+
instance.def = ty::InstanceKind::Virtual(method_id, 0);
383+
let abstract_trait_args =
384+
tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
385+
instance.args = instance.args.rebase_onto(tcx, ancestor, abstract_trait_args);
398386
} else if tcx.is_closure_like(instance.def_id()) {
399387
// We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
400388
// instantiate it, and take the type of its only method as our own.
@@ -452,3 +440,36 @@ pub fn transform_instance<'tcx>(
452440

453441
instance
454442
}
443+
444+
fn implemented_method<'tcx>(
445+
tcx: TyCtxt<'tcx>,
446+
instance: Instance<'tcx>,
447+
) -> Option<(ty::EarlyBinder<'tcx, TraitRef<'tcx>>, DefId, DefId)> {
448+
let trait_ref;
449+
let method_id;
450+
let trait_id;
451+
let trait_method;
452+
let ancestor = if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) {
453+
// Implementation in an `impl` block
454+
trait_ref = tcx.impl_trait_ref(impl_id)?;
455+
let impl_method = tcx.associated_item(instance.def_id());
456+
method_id = impl_method.trait_item_def_id?;
457+
trait_method = tcx.associated_item(method_id);
458+
trait_id = trait_ref.skip_binder().def_id;
459+
impl_id
460+
} else if let InstanceKind::Item(def_id) = instance.def
461+
&& let Some(trait_method_bound) = tcx.opt_associated_item(def_id)
462+
{
463+
// Provided method in a `trait` block
464+
trait_method = trait_method_bound;
465+
method_id = instance.def_id();
466+
trait_id = tcx.trait_of_item(method_id)?;
467+
trait_ref = ty::EarlyBinder::bind(TraitRef::from_method(tcx, trait_id, instance.args));
468+
trait_id
469+
} else {
470+
return None;
471+
};
472+
let vtable_possible =
473+
traits::is_vtable_safe_method(tcx, trait_id, trait_method) && tcx.is_object_safe(trait_id);
474+
vtable_possible.then_some((trait_ref, method_id, ancestor))
475+
}

tests/ui/sanitizer/cfi-supertraits.rs

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
trait Parent1 {
1717
type P1;
1818
fn p1(&self) -> Self::P1;
19+
fn d(&self) -> i32 {
20+
42
21+
}
1922
}
2023

2124
trait Parent2 {
@@ -60,14 +63,17 @@ fn main() {
6063
x.c();
6164
x.p1();
6265
x.p2();
66+
x.d();
6367
// Parents can be created and access their methods.
6468
let y = &Foo as &dyn Parent1<P1=u16>;
6569
y.p1();
70+
y.d();
6671
let z = &Foo as &dyn Parent2<P2=u32>;
6772
z.p2();
6873
// Trait upcasting works
6974
let x1 = x as &dyn Parent1<P1=u16>;
7075
x1.p1();
76+
x1.d();
7177
let x2 = x as &dyn Parent2<P2=u32>;
7278
x2.p2();
7379
}

0 commit comments

Comments
 (0)