Skip to content

Commit 9cb3688

Browse files
authored
Rollup merge of #128580 - compiler-errors:cfi-param-env, r=lcnr
Use `ParamEnv::reveal_all` in CFI I left a huge comment for why this ICEs in the test I committed. `typeid_for_instance` should only be called on monomorphic instances during codegen, and we should just be using `ParamEnv::reveal_all()` rather than the param-env of the instance itself. I added an assertion to ensure that we only do this for fully substituted instances (this may break with polymorphization, but I kinda don't care lol). Fixes #114160 cc `@rcvalle`
2 parents 8cbf1c1 + b0beb64 commit 9cb3688

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_middle::bug;
9-
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
9+
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
1010
use rustc_target::abi::call::{Conv, FnAbi, PassMode};
1111
use tracing::instrument;
1212

@@ -112,11 +112,12 @@ pub fn typeid_for_instance<'tcx>(
112112
instance: Instance<'tcx>,
113113
options: TypeIdOptions,
114114
) -> String {
115+
assert!(!instance.has_non_region_param(), "{instance:#?} must be fully monomorphic");
115116
let transform_ty_options = TransformTyOptions::from_bits(options.bits())
116117
.unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
117118
let instance = transform_instance(tcx, instance, transform_ty_options);
118119
let fn_abi = tcx
119-
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
120+
.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((instance, ty::List::empty())))
120121
.unwrap_or_else(|error| {
121122
bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
122123
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//@ needs-sanitizer-cfi
2+
//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
3+
//@ no-prefer-dynamic
4+
//@ only-x86_64-unknown-linux-gnu
5+
//@ build-pass
6+
7+
// See comment below for why this test exists.
8+
9+
trait Tr<U> {
10+
type Projection;
11+
}
12+
13+
impl<F, U> Tr<U> for F
14+
where
15+
F: Fn() -> U
16+
{
17+
type Projection = U;
18+
}
19+
20+
fn test<B: Tr<U>, U>(b: B) -> B::Projection
21+
{
22+
todo!()
23+
}
24+
25+
fn main() {
26+
fn rpit_fn() -> impl Sized {}
27+
28+
// When CFI runs, it tries to compute the signature of the call. This
29+
// ends up giving us a signature of:
30+
// `fn test::<rpit_fn, ()>() -> <rpit_fn as Tr<()>>::Projection`,
31+
// where `rpit_fn` is the ZST FnDef for the function. However, we were
32+
// previously using a Reveal::UserFacing param-env. This means that the
33+
// `<rpit_fn as Tr<()>>::Projection` return type is impossible to normalize,
34+
// since it would require proving `rpit_fn: Fn() -> ()`, but we cannot
35+
// prove that the `impl Sized` opaque is `()` with a user-facing param-env.
36+
// This leads to a normalization error, and then an ICE.
37+
//
38+
// Side-note:
39+
// So why is the second generic of `test` "`()`", and not the
40+
// `impl Sized` since we inferred it from the return type of `rpit_fn`
41+
// during typeck? Well, that's because we're using the generics from the
42+
// terminator of the MIR, which has had the RevealAll pass performed on it.
43+
let _ = test(rpit_fn);
44+
}

0 commit comments

Comments
 (0)