Skip to content

Commit fb6c823

Browse files
committed
CFI: Pad out associated type resolution with erased lifetimes
`trait_object_ty` assumed that associated types would be fully determined by the trait. This is *almost* true - const parameters and type parameters are no longer allowed, but lifetime parameters are. Since we erase all lifetime parameters anyways, instantiate it with as many erased regions as it needs. Fixes: #123053
1 parent 60b5ca6 commit fb6c823

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1152,8 +1152,8 @@ pub fn typeid_for_instance<'tcx>(
11521152

11531153
let fn_abi = tcx
11541154
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
1155-
.unwrap_or_else(|instance| {
1156-
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
1155+
.unwrap_or_else(|error| {
1156+
bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
11571157
});
11581158

11591159
typeid_for_fnabi(tcx, fn_abi, options)
@@ -1182,6 +1182,7 @@ fn strip_receiver_auto<'tcx>(
11821182
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
11831183
}
11841184

1185+
#[instrument(skip(tcx), ret)]
11851186
fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> {
11861187
assert!(!poly_trait_ref.has_non_region_param());
11871188
let principal_pred = poly_trait_ref.map_bound(|trait_ref| {
@@ -1194,11 +1195,22 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
11941195
.filter(|item| item.kind == ty::AssocKind::Type)
11951196
.map(move |assoc_ty| {
11961197
super_poly_trait_ref.map_bound(|super_trait_ref| {
1197-
let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args);
1198+
// While vtable-safe projections can't have const or type parameters that
1199+
// aren't part of the trait_ref, they *can* have additional regions. Pad out
1200+
// the projection with erased regions.
1201+
let missing_args =
1202+
tcx.generics_of(assoc_ty.def_id).count() - super_trait_ref.args.len();
1203+
let extra_regions =
1204+
iter::repeat(tcx.lifetimes.re_erased.into()).take(missing_args);
1205+
let alias_args = tcx.mk_args_from_iter(
1206+
super_trait_ref.args.into_iter().chain(extra_regions),
1207+
);
1208+
let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, alias_args);
11981209
let resolved = tcx.normalize_erasing_regions(
11991210
ty::ParamEnv::reveal_all(),
12001211
alias_ty.to_ty(tcx),
12011212
);
1213+
debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
12021214
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
12031215
def_id: assoc_ty.def_id,
12041216
args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Regression test for issue 123053, where associated types with lifetimes caused generation of the
2+
// trait object type to fail, causing an ICE.
3+
//
4+
//@ needs-sanitizer-cfi
5+
//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi --edition=2021
6+
//@ no-prefer-dynamic
7+
//@ only-x86_64-unknown-linux-gnu
8+
//@ build-pass
9+
10+
trait Iterable {
11+
type Item<'a>
12+
where
13+
Self: 'a;
14+
type Iter<'a>: Iterator<Item = Self::Item<'a>>
15+
where
16+
Self: 'a;
17+
18+
fn iter<'a>(&'a self) -> Self::Iter<'a>;
19+
}
20+
21+
impl<T> Iterable for [T] {
22+
type Item<'a> = <std::slice::Iter<'a, T> as Iterator>::Item where T: 'a;
23+
type Iter<'a> = std::slice::Iter<'a, T> where T: 'a;
24+
25+
fn iter<'a>(&'a self) -> Self::Iter<'a> {
26+
self.iter()
27+
}
28+
}
29+
30+
fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option<I::Item<'a>> {
31+
it.iter().next()
32+
}
33+
34+
fn main() {
35+
let v = vec![1, 2, 3];
36+
37+
assert_eq!(Some(&1), get_first(&*v));
38+
}

0 commit comments

Comments
 (0)