Skip to content

Commit f9ba552

Browse files
authored
Rollup merge of rust-lang#130863 - compiler-errors:relax-codegen-dyn-assert, r=lcnr
Relax a debug assertion for dyn principal *equality* in codegen Maybe this sucks and I should just bite the bullet and use `infcx.sub` here. Thoughts? r? lcnr Fixes rust-lang#130855
2 parents 360f7d7 + cbb5047 commit f9ba552

File tree

5 files changed

+66
-20
lines changed

5 files changed

+66
-20
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3451,6 +3451,7 @@ dependencies = [
34513451
"rustc_span",
34523452
"rustc_symbol_mangling",
34533453
"rustc_target",
3454+
"rustc_trait_selection",
34543455
"rustc_type_ir",
34553456
"serde_json",
34563457
"smallvec",

compiler/rustc_codegen_cranelift/src/unsize.rs

+3-14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize`
44
5+
use rustc_codegen_ssa::base::validate_trivial_unsize;
56
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
67

78
use crate::base::codegen_panic_nounwind;
@@ -34,20 +35,8 @@ pub(crate) fn unsized_info<'tcx>(
3435
let old_info =
3536
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
3637
if data_a.principal_def_id() == data_b.principal_def_id() {
37-
// Codegen takes advantage of the additional assumption, where if the
38-
// principal trait def id of what's being casted doesn't change,
39-
// then we don't need to adjust the vtable at all. This
40-
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
41-
// requires that `A = B`; we don't allow *upcasting* objects
42-
// between the same trait with different args. If we, for
43-
// some reason, were to relax the `Unsize` trait, it could become
44-
// unsound, so let's assert here that the trait refs are *equal*.
45-
//
46-
// We can use `assert_eq` because the binders should have been anonymized,
47-
// and because higher-ranked equality now requires the binders are equal.
48-
debug_assert_eq!(
49-
data_a.principal(),
50-
data_b.principal(),
38+
debug_assert!(
39+
validate_trivial_unsize(fx.tcx, data_a, data_b),
5140
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
5241
);
5342
return old_info;

compiler/rustc_codegen_ssa/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ rustc_session = { path = "../rustc_session" }
3434
rustc_span = { path = "../rustc_span" }
3535
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
3636
rustc_target = { path = "../rustc_target" }
37+
rustc_trait_selection = { path = "../rustc_trait_selection" }
3738
rustc_type_ir = { path = "../rustc_type_ir" }
3839
serde_json = "1.0.59"
3940
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }

compiler/rustc_codegen_ssa/src/base.rs

+53-6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
2727
use rustc_span::symbol::sym;
2828
use rustc_span::{DUMMY_SP, Symbol};
2929
use rustc_target::abi::FIRST_VARIANT;
30+
use rustc_trait_selection::infer::at::ToTrace;
31+
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
32+
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
3033
use tracing::{debug, info};
3134

3235
use crate::assert_module_sources::CguReuse;
@@ -101,6 +104,54 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
101104
bx.sext(cmp, ret_ty)
102105
}
103106

107+
/// Codegen takes advantage of the additional assumption, where if the
108+
/// principal trait def id of what's being casted doesn't change,
109+
/// then we don't need to adjust the vtable at all. This
110+
/// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
111+
/// requires that `A = B`; we don't allow *upcasting* objects
112+
/// between the same trait with different args. If we, for
113+
/// some reason, were to relax the `Unsize` trait, it could become
114+
/// unsound, so let's validate here that the trait refs are subtypes.
115+
pub fn validate_trivial_unsize<'tcx>(
116+
tcx: TyCtxt<'tcx>,
117+
source_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
118+
target_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
119+
) -> bool {
120+
match (source_data.principal(), target_data.principal()) {
121+
(Some(hr_source_principal), Some(hr_target_principal)) => {
122+
let infcx = tcx.infer_ctxt().build();
123+
let universe = infcx.universe();
124+
let ocx = ObligationCtxt::new(&infcx);
125+
infcx.enter_forall(hr_target_principal, |target_principal| {
126+
let source_principal = infcx.instantiate_binder_with_fresh_vars(
127+
DUMMY_SP,
128+
BoundRegionConversionTime::HigherRankedType,
129+
hr_source_principal,
130+
);
131+
let Ok(()) = ocx.eq_trace(
132+
&ObligationCause::dummy(),
133+
ty::ParamEnv::reveal_all(),
134+
ToTrace::to_trace(
135+
&ObligationCause::dummy(),
136+
hr_target_principal,
137+
hr_source_principal,
138+
),
139+
target_principal,
140+
source_principal,
141+
) else {
142+
return false;
143+
};
144+
if !ocx.select_all_or_error().is_empty() {
145+
return false;
146+
}
147+
infcx.leak_check(universe, None).is_ok()
148+
})
149+
}
150+
(None, None) => true,
151+
_ => false,
152+
}
153+
}
154+
104155
/// Retrieves the information we are losing (making dynamic) in an unsizing
105156
/// adjustment.
106157
///
@@ -133,12 +184,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
133184
// between the same trait with different args. If we, for
134185
// some reason, were to relax the `Unsize` trait, it could become
135186
// unsound, so let's assert here that the trait refs are *equal*.
136-
//
137-
// We can use `assert_eq` because the binders should have been anonymized,
138-
// and because higher-ranked equality now requires the binders are equal.
139-
debug_assert_eq!(
140-
data_a.principal(),
141-
data_b.principal(),
187+
debug_assert!(
188+
validate_trivial_unsize(cx.tcx(), data_a, data_b),
142189
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
143190
);
144191

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//@ build-pass
2+
3+
// Regression test for an overly aggressive assertion in #130855.
4+
5+
fn main() {
6+
let subtype: &(dyn for<'a> Fn(&'a i32) -> &'a i32) = &|x| x;
7+
let supertype: &(dyn Fn(&'static i32) -> &'static i32) = subtype;
8+
}

0 commit comments

Comments
 (0)