Skip to content

Commit ead93d8

Browse files
committed
make infcx optional in canonicalizer
This doesn't change behavior. It should prevent unintentional resolution of inference variables during canonicalization, which previously caused a soundness bug. See PR description for more.
1 parent 23a0a44 commit ead93d8

File tree

2 files changed

+41
-47
lines changed

2 files changed

+41
-47
lines changed

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

+31-45
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<'tcx> InferCtxt<'tcx> {
6060
{
6161
Canonicalizer::canonicalize(
6262
value,
63-
self,
63+
Some(self),
6464
self.tcx,
6565
&CanonicalizeAllFreeRegionsPreservingUniverses,
6666
query_state,
@@ -99,7 +99,7 @@ impl<'tcx> InferCtxt<'tcx> {
9999
let mut query_state = OriginalQueryValues::default();
100100
Canonicalizer::canonicalize(
101101
value,
102-
self,
102+
Some(self),
103103
self.tcx,
104104
&CanonicalizeQueryResponse,
105105
&mut query_state,
@@ -113,7 +113,7 @@ impl<'tcx> InferCtxt<'tcx> {
113113
let mut query_state = OriginalQueryValues::default();
114114
Canonicalizer::canonicalize(
115115
value,
116-
self,
116+
Some(self),
117117
self.tcx,
118118
&CanonicalizeUserTypeAnnotation,
119119
&mut query_state,
@@ -153,11 +153,11 @@ impl<'tcx> InferCtxt<'tcx> {
153153
self.tcx,
154154
param_env,
155155
query_state,
156-
|query_state| {
156+
|tcx, param_env, query_state| {
157157
Canonicalizer::canonicalize(
158158
param_env,
159-
self,
160-
self.tcx,
159+
None,
160+
tcx,
161161
&CanonicalizeFreeRegionsOtherThanStatic,
162162
query_state,
163163
)
@@ -167,7 +167,7 @@ impl<'tcx> InferCtxt<'tcx> {
167167
Canonicalizer::canonicalize_with_base(
168168
base,
169169
value,
170-
self,
170+
Some(self),
171171
self.tcx,
172172
canonicalize_region_mode,
173173
query_state,
@@ -204,9 +204,10 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
204204
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
205205
mut r: ty::Region<'tcx>,
206206
) -> ty::Region<'tcx> {
207+
let infcx = canonicalizer.infcx.unwrap();
208+
207209
if let ty::ReVar(vid) = *r {
208-
r = canonicalizer
209-
.infcx
210+
r = infcx
210211
.inner
211212
.borrow_mut()
212213
.unwrap_region_constraints()
@@ -226,7 +227,8 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
226227
),
227228

228229
ty::ReVar(vid) => {
229-
let universe = canonicalizer.region_var_universe(vid);
230+
let universe =
231+
infcx.inner.borrow_mut().unwrap_region_constraints().var_universe(vid);
230232
canonicalizer.canonical_var_for_region(
231233
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
232234
r,
@@ -319,7 +321,7 @@ impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
319321
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
320322
r: ty::Region<'tcx>,
321323
) -> ty::Region<'tcx> {
322-
let universe = canonicalizer.infcx.universe_of_region(r);
324+
let universe = canonicalizer.infcx.unwrap().universe_of_region(r);
323325
canonicalizer.canonical_var_for_region(
324326
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
325327
r,
@@ -356,7 +358,8 @@ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
356358
}
357359

358360
struct Canonicalizer<'cx, 'tcx> {
359-
infcx: &'cx InferCtxt<'tcx>,
361+
/// Set to `None` to disable the resolution of inference variables.
362+
infcx: Option<&'cx InferCtxt<'tcx>>,
360363
tcx: TyCtxt<'tcx>,
361364
variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
362365
query_state: &'cx mut OriginalQueryValues<'tcx>,
@@ -410,14 +413,14 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
410413
// We need to canonicalize the *root* of our ty var.
411414
// This is so that our canonical response correctly reflects
412415
// any equated inference vars correctly!
413-
let root_vid = self.infcx.root_var(vid);
416+
let root_vid = self.infcx.unwrap().root_var(vid);
414417
if root_vid != vid {
415-
t = Ty::new_var(self.infcx.tcx, root_vid);
418+
t = Ty::new_var(self.tcx, root_vid);
416419
vid = root_vid;
417420
}
418421

419422
debug!("canonical: type var found with vid {:?}", vid);
420-
match self.infcx.probe_ty_var(vid) {
423+
match self.infcx.unwrap().probe_ty_var(vid) {
421424
// `t` could be a float / int variable; canonicalize that instead.
422425
Ok(t) => {
423426
debug!("(resolved to {:?})", t);
@@ -442,7 +445,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
442445
}
443446

444447
ty::Infer(ty::IntVar(vid)) => {
445-
let nt = self.infcx.opportunistic_resolve_int_var(vid);
448+
let nt = self.infcx.unwrap().opportunistic_resolve_int_var(vid);
446449
if nt != t {
447450
return self.fold_ty(nt);
448451
} else {
@@ -453,7 +456,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
453456
}
454457
}
455458
ty::Infer(ty::FloatVar(vid)) => {
456-
let nt = self.infcx.opportunistic_resolve_float_var(vid);
459+
let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid);
457460
if nt != t {
458461
return self.fold_ty(nt);
459462
} else {
@@ -524,14 +527,14 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
524527
// We need to canonicalize the *root* of our const var.
525528
// This is so that our canonical response correctly reflects
526529
// any equated inference vars correctly!
527-
let root_vid = self.infcx.root_const_var(vid);
530+
let root_vid = self.infcx.unwrap().root_const_var(vid);
528531
if root_vid != vid {
529-
ct = ty::Const::new_var(self.infcx.tcx, root_vid, ct.ty());
532+
ct = ty::Const::new_var(self.tcx, root_vid, ct.ty());
530533
vid = root_vid;
531534
}
532535

533536
debug!("canonical: const var found with vid {:?}", vid);
534-
match self.infcx.probe_const_var(vid) {
537+
match self.infcx.unwrap().probe_const_var(vid) {
535538
Ok(c) => {
536539
debug!("(resolved to {:?})", c);
537540
return self.fold_const(c);
@@ -552,8 +555,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
552555
}
553556
}
554557
ty::ConstKind::Infer(InferConst::EffectVar(vid)) => {
555-
match self.infcx.probe_effect_var(vid) {
556-
Some(value) => return self.fold_const(value.as_const(self.infcx.tcx)),
558+
match self.infcx.unwrap().probe_effect_var(vid) {
559+
Some(value) => return self.fold_const(value.as_const(self.tcx)),
557560
None => {
558561
return self.canonicalize_const_var(
559562
CanonicalVarInfo { kind: CanonicalVarKind::Effect },
@@ -596,7 +599,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
596599
/// `canonicalize_query` and `canonicalize_response`.
597600
fn canonicalize<V>(
598601
value: V,
599-
infcx: &InferCtxt<'tcx>,
602+
infcx: Option<&InferCtxt<'tcx>>,
600603
tcx: TyCtxt<'tcx>,
601604
canonicalize_region_mode: &dyn CanonicalizeMode,
602605
query_state: &mut OriginalQueryValues<'tcx>,
@@ -623,7 +626,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
623626
fn canonicalize_with_base<U, V>(
624627
base: Canonical<'tcx, U>,
625628
value: V,
626-
infcx: &InferCtxt<'tcx>,
629+
infcx: Option<&InferCtxt<'tcx>>,
627630
tcx: TyCtxt<'tcx>,
628631
canonicalize_region_mode: &dyn CanonicalizeMode,
629632
query_state: &mut OriginalQueryValues<'tcx>,
@@ -826,11 +829,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
826829
)
827830
}
828831

829-
/// Returns the universe in which `vid` is defined.
830-
fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex {
831-
self.infcx.inner.borrow_mut().unwrap_region_constraints().var_universe(vid)
832-
}
833-
834832
/// Creates a canonical variable (with the given `info`)
835833
/// representing the region `r`; return a region referencing it.
836834
fn canonical_var_for_region(
@@ -848,14 +846,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
848846
/// *that*. Otherwise, create a new canonical variable for
849847
/// `ty_var`.
850848
fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> {
851-
let infcx = self.infcx;
852-
let bound_to = infcx.shallow_resolve(ty_var);
853-
if bound_to != ty_var {
854-
self.fold_ty(bound_to)
855-
} else {
856-
let var = self.canonical_var(info, ty_var.into());
857-
Ty::new_bound(self.tcx, self.binder_index, var.into())
858-
}
849+
let var = self.canonical_var(info, ty_var.into());
850+
Ty::new_bound(self.tcx, self.binder_index, var.into())
859851
}
860852

861853
/// Given a type variable `const_var` of the given kind, first check
@@ -867,13 +859,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
867859
info: CanonicalVarInfo<'tcx>,
868860
const_var: ty::Const<'tcx>,
869861
) -> ty::Const<'tcx> {
870-
let infcx = self.infcx;
871-
let bound_to = infcx.shallow_resolve(const_var);
872-
if bound_to != const_var {
873-
self.fold_const(bound_to)
874-
} else {
875-
let var = self.canonical_var(info, const_var.into());
876-
ty::Const::new_bound(self.tcx, self.binder_index, var, self.fold_ty(const_var.ty()))
877-
}
862+
let var = self.canonical_var(info, const_var.into());
863+
ty::Const::new_bound(self.tcx, self.binder_index, var, self.fold_ty(const_var.ty()))
878864
}
879865
}

compiler/rustc_middle/src/infer/canonical.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,20 @@ pub struct CanonicalParamEnvCache<'tcx> {
306306
}
307307

308308
impl<'tcx> CanonicalParamEnvCache<'tcx> {
309+
/// Gets the cached canonical form of `key` or executes
310+
/// `canonicalize_op` and caches the result if not present.
311+
///
312+
/// `canonicalize_op` is intentionally not allowed to be a closure to
313+
/// statically prevent it from capturing `InferCtxt` and resolving
314+
/// inference variables, which invalidates the cache.
309315
pub fn get_or_insert(
310316
&self,
311317
tcx: TyCtxt<'tcx>,
312318
key: ty::ParamEnv<'tcx>,
313319
state: &mut OriginalQueryValues<'tcx>,
314-
canonicalize_op: impl FnOnce(
320+
canonicalize_op: fn(
321+
TyCtxt<'tcx>,
322+
ty::ParamEnv<'tcx>,
315323
&mut OriginalQueryValues<'tcx>,
316324
) -> Canonical<'tcx, ty::ParamEnv<'tcx>>,
317325
) -> Canonical<'tcx, ty::ParamEnv<'tcx>> {
@@ -336,7 +344,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
336344
canonical.clone()
337345
}
338346
Entry::Vacant(e) => {
339-
let canonical = canonicalize_op(state);
347+
let canonical = canonicalize_op(tcx, key, state);
340348
let OriginalQueryValues { var_values, universe_map } = state;
341349
assert_eq!(universe_map.len(), 1);
342350
e.insert((canonical.clone(), tcx.arena.alloc_slice(var_values)));

0 commit comments

Comments
 (0)