diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 868c6f11b68dc..e112f0eaf2a62 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { let assumptions = elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied()); - for &(constraint, constraint_category) in constraints { + for &(constraint, constraint_category, _) in constraints { constraint.iter_outlives().for_each(|predicate| { self.convert(predicate, constraint_category, &assumptions); }); @@ -205,6 +205,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { t1, r2, constraint_category, + ty::VisibleForLeakCheck::Yes, ); } @@ -296,7 +297,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // FIXME(higher_ranked_auto): What should we do with the assumptions here? if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints { next_outlives_predicates.extend(constraints.iter().flat_map( - |(constraint, category)| { + |(constraint, category, _)| { constraint.iter_outlives().map(|outlives| (outlives, *category)) }, )); @@ -315,6 +316,7 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' a: ty::Region<'tcx>, b: ty::Region<'tcx>, constraint_category: ConstraintCategory<'tcx>, + _vis: ty::VisibleForLeakCheck, ) { let b = self.to_region_vid(b); let a = self.to_region_vid(a); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 32610619fe713..6cedd5ca5265c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -709,6 +709,7 @@ fn ty_known_to_outlive<'tcx>( sub_region: region, sup_type: ty, origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None), + visible_for_leak_check: ty::VisibleForLeakCheck::Yes, }); }) } @@ -728,6 +729,7 @@ fn region_known_to_outlive<'tcx>( SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a, + ty::VisibleForLeakCheck::Yes, ); }) } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 7c3511e91d79d..f6a784c84d683 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -490,7 +490,12 @@ pub(crate) fn coerce_unsized_info<'tcx>( } (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { - infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a); + infcx.sub_regions( + SubregionOrigin::RelateObjectBound(span), + r_b, + r_a, + ty::VisibleForLeakCheck::Yes, + ); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty)) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5203b4ee5d99f..cf84010d28729 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -188,14 +188,14 @@ impl<'tcx> InferCtxt<'tcx> { let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; - for (constraint, _category) in &query_response.value.region_constraints.constraints { + for (constraint, _category, vis) in &query_response.value.region_constraints.constraints { let constraint = instantiate_value(self.tcx, &result_args, *constraint); match constraint { ty::RegionConstraint::Outlives(predicate) => { - self.register_outlives_constraint(predicate, cause); + self.register_outlives_constraint(predicate, *vis, cause); } ty::RegionConstraint::Eq(predicate) => { - self.register_region_eq_constraint(predicate, cause); + self.register_region_eq_constraint(predicate, *vis, cause); } } } @@ -288,6 +288,7 @@ impl<'tcx> InferCtxt<'tcx> { output_query_region_constraints.constraints.push(( ty::RegionEqPredicate(v_o.into(), v_r).into(), constraint_category, + ty::VisibleForLeakCheck::Yes, )); } } @@ -586,6 +587,7 @@ impl<'tcx> InferCtxt<'tcx> { SubregionOrigin::RelateRegionParamBound(cause.span, None), v1, v2, + ty::VisibleForLeakCheck::Yes, ); } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { @@ -623,20 +625,23 @@ pub fn make_query_region_constraints<'tcx>( | ConstraintKind::RegSubReg => { // Swap regions because we are going from sub (<=) to outlives (>=). let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub).into(); - (constraint, origin.to_constraint_category()) + (constraint, origin.to_constraint_category(), c.visible_for_leak_check) } ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => { let constraint = ty::RegionEqPredicate(c.sup, c.sub).into(); - (constraint, origin.to_constraint_category()) + (constraint, origin.to_constraint_category(), c.visible_for_leak_check) } }) - .chain(outlives_obligations.into_iter().map(|obl| { - ( - ty::OutlivesPredicate(obl.sup_type.into(), obl.sub_region).into(), - obl.origin.to_constraint_category(), - ) - })) + .chain(outlives_obligations.into_iter().map( + |TypeOutlivesConstraint { sub_region, sup_type, origin, visible_for_leak_check }| { + ( + ty::OutlivesPredicate(sup_type.into(), sub_region).into(), + origin.to_constraint_category(), + visible_for_leak_check, + ) + }, + )) .collect(); QueryRegionConstraints { constraints, assumptions } diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index fada30ff30633..cab5efc4b025a 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -256,24 +256,44 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.probe(|_| probe()) } - fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>, span: Span) { + fn sub_regions( + &self, + sub: ty::Region<'tcx>, + sup: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, + span: Span, + ) { self.inner.borrow_mut().unwrap_region_constraints().make_subregion( SubregionOrigin::RelateRegionParamBound(span, None), sub, sup, + vis, ); } - fn equate_regions(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, span: Span) { + fn equate_regions( + &self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, + span: Span, + ) { self.inner.borrow_mut().unwrap_region_constraints().make_eqregion( SubregionOrigin::RelateRegionParamBound(span, None), a, b, + vis, ); } - fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>, span: Span) { - self.register_type_outlives_constraint(ty, r, &ObligationCause::dummy_with_span(span)); + fn register_ty_outlives( + &self, + ty: Ty<'tcx>, + r: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, + span: Span, + ) { + self.register_type_outlives_constraint(ty, r, vis, &ObligationCause::dummy_with_span(span)); } type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 26c03066c7e40..dedff9ceddb8c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -510,6 +510,7 @@ pub struct TypeOutlivesConstraint<'tcx> { pub sub_region: ty::Region<'tcx>, pub sup_type: Ty<'tcx>, pub origin: SubregionOrigin<'tcx>, + pub visible_for_leak_check: ty::VisibleForLeakCheck, } /// Used to configure inference contexts before their creation. @@ -698,8 +699,9 @@ impl<'tcx> InferCtxt<'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, ) { - self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); + self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b, vis); } #[instrument(skip(self), level = "debug")] @@ -708,8 +710,9 @@ impl<'tcx> InferCtxt<'tcx> { origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, ) { - self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b); + self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b, vis); } /// Processes a `Coerce` predicate from the fulfillment context. diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index e98bee3b12cde..eb30d2b795bc1 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -85,14 +85,15 @@ impl<'tcx> InferCtxt<'tcx> { pub fn register_outlives_constraint( &self, ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>, + vis: ty::VisibleForLeakCheck, cause: &ObligationCause<'tcx>, ) { match arg.kind() { ty::GenericArgKind::Lifetime(r1) => { - self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), cause); + self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), vis, cause); } ty::GenericArgKind::Type(ty1) => { - self.register_type_outlives_constraint(ty1, r2, cause); + self.register_type_outlives_constraint(ty1, r2, vis, cause); } ty::GenericArgKind::Const(_) => unreachable!(), } @@ -101,24 +102,26 @@ impl<'tcx> InferCtxt<'tcx> { pub fn register_region_eq_constraint( &self, ty::RegionEqPredicate(r_a, r_b): ty::RegionEqPredicate<'tcx>, + vis: ty::VisibleForLeakCheck, cause: &ObligationCause<'tcx>, ) { let origin = SubregionOrigin::from_obligation_cause(cause, || { SubregionOrigin::RelateRegionParamBound(cause.span, None) }); - self.equate_regions(origin, r_a, r_b); + self.equate_regions(origin, r_a, r_b, vis); } pub fn register_region_outlives_constraint( &self, ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>, + vis: ty::VisibleForLeakCheck, cause: &ObligationCause<'tcx>, ) { let origin = SubregionOrigin::from_obligation_cause(cause, || { SubregionOrigin::RelateRegionParamBound(cause.span, None) }); // `'a: 'b` ==> `'b <= 'a` - self.sub_regions(origin, r_b, r_a); + self.sub_regions(origin, r_b, r_a, vis); } /// Registers that the given region obligation must be resolved @@ -140,6 +143,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, sup_type: Ty<'tcx>, sub_region: Region<'tcx>, + vis: ty::VisibleForLeakCheck, cause: &ObligationCause<'tcx>, ) { // `is_global` means the type has no params, infer, placeholder, or non-`'static` @@ -172,6 +176,7 @@ impl<'tcx> InferCtxt<'tcx> { sup_type, sub_region, origin, + visible_for_leak_check: vis, }); } @@ -233,7 +238,9 @@ impl<'tcx> InferCtxt<'tcx> { ); } - for TypeOutlivesConstraint { sup_type, sub_region, origin } in my_region_obligations { + for TypeOutlivesConstraint { sup_type, sub_region, origin, visible_for_leak_check } in + my_region_obligations + { let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region)); let ty::OutlivesPredicate(sup_type, sub_region) = deeply_normalize_ty(outlives, origin.clone()) @@ -264,7 +271,13 @@ impl<'tcx> InferCtxt<'tcx> { outlives_env.known_type_outlives(), ); let category = origin.to_constraint_category(); - outlives.type_must_outlive(origin, sup_type, sub_region, category); + outlives.type_must_outlive( + origin, + sup_type, + sub_region, + category, + visible_for_leak_check, + ); } } @@ -296,6 +309,7 @@ pub trait TypeOutlivesDelegate<'tcx> { a: ty::Region<'tcx>, b: ty::Region<'tcx>, constraint_category: ConstraintCategory<'tcx>, + vis: ty::VisibleForLeakCheck, ); fn push_verify( @@ -345,12 +359,13 @@ where ty: Ty<'tcx>, region: ty::Region<'tcx>, category: ConstraintCategory<'tcx>, + vis: ty::VisibleForLeakCheck, ) { assert!(!ty.has_escaping_bound_vars()); let mut components = smallvec![]; push_outlives_components(self.tcx, ty, &mut components); - self.components_must_outlive(origin, &components, region, category); + self.components_must_outlive(origin, &components, region, category, vis); } fn components_must_outlive( @@ -359,12 +374,14 @@ where components: &[Component>], region: ty::Region<'tcx>, category: ConstraintCategory<'tcx>, + vis: ty::VisibleForLeakCheck, ) { for component in components.iter() { let origin = origin.clone(); match component { Component::Region(region1) => { - self.delegate.push_sub_region_constraint(origin, region, *region1, category); + self.delegate + .push_sub_region_constraint(origin, region, *region1, category, vis); } Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); @@ -372,9 +389,11 @@ where Component::Placeholder(placeholder_ty) => { self.placeholder_ty_must_outlive(origin, region, *placeholder_ty); } - Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty), + Component::Alias(alias_ty) => { + self.alias_ty_must_outlive(origin, region, *alias_ty, vis) + } Component::EscapingAlias(subcomponents) => { - self.components_must_outlive(origin, subcomponents, region, category); + self.components_must_outlive(origin, subcomponents, region, category, vis); } Component::UnresolvedInferenceVariable(v) => { // Ignore this, we presume it will yield an error later, @@ -424,6 +443,7 @@ where origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, alias_ty: ty::AliasTy<'tcx>, + vis: ty::VisibleForLeakCheck, ) { // An optimization for a common case with opaque types. if alias_ty.args.is_empty() { @@ -486,7 +506,7 @@ where { debug!("no declared bounds"); let opt_variances = self.tcx.opt_alias_variances(kind); - self.args_must_outlive(alias_ty.args, origin, region, opt_variances); + self.args_must_outlive(alias_ty.args, origin, region, opt_variances, vis); return; } @@ -518,7 +538,7 @@ where debug!(?unique_bound); debug!("unique declared bound appears in trait ref"); let category = origin.to_constraint_category(); - self.delegate.push_sub_region_constraint(origin, region, unique_bound, category); + self.delegate.push_sub_region_constraint(origin, region, unique_bound, category, vis); return; } @@ -539,6 +559,7 @@ where origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, opt_variances: Option<&[ty::Variance]>, + vis: ty::VisibleForLeakCheck, ) { let constraint = origin.to_constraint_category(); for (index, arg) in args.iter().enumerate() { @@ -555,11 +576,12 @@ where region, lt, constraint, + vis, ); } } GenericArgKind::Type(ty) => { - self.type_must_outlive(origin.clone(), ty, region, constraint); + self.type_must_outlive(origin.clone(), ty, region, constraint, vis); } GenericArgKind::Const(_) => { // Const parameters don't impose constraints. @@ -576,8 +598,9 @@ impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> { a: ty::Region<'tcx>, b: ty::Region<'tcx>, _constraint_category: ConstraintCategory<'tcx>, + vis: ty::VisibleForLeakCheck, ) { - self.sub_regions(origin, a, b) + self.sub_regions(origin, a, b, vis) } fn push_verify( diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 81a3ca6755d20..2cbf4332038a9 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -369,7 +369,11 @@ impl<'tcx> MiniGraph<'tcx> { Self::iterate_region_constraints( region_constraints, only_consider_snapshot, - |target, source| { + |target, source, vis| { + if vis == ty::VisibleForLeakCheck::No { + return; + } + let source_node = Self::add_node(&mut nodes, source); let target_node = Self::add_node(&mut nodes, target); edges.push((source_node, target_node)); @@ -384,7 +388,7 @@ impl<'tcx> MiniGraph<'tcx> { fn iterate_region_constraints( region_constraints: &RegionConstraintCollector<'_, 'tcx>, only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, - mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>), + mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>, ty::VisibleForLeakCheck), ) { if let Some(snapshot) = only_consider_snapshot { for undo_entry in @@ -392,10 +396,11 @@ impl<'tcx> MiniGraph<'tcx> { { match undo_entry { &AddConstraint(i) => { - region_constraints.data().constraints[i] - .0 - .iter_outlives() - .for_each(|c| each_edge(c.sub, c.sup)); + region_constraints.data().constraints[i].0.iter_outlives().for_each( + |Constraint { kind: _, sub, sup, visible_for_leak_check }| { + each_edge(sub, sup, visible_for_leak_check) + }, + ); } &AddVerify(i) => span_bug!( region_constraints.data().verifys[i].origin.span(), @@ -410,7 +415,9 @@ impl<'tcx> MiniGraph<'tcx> { .constraints .iter() .flat_map(|(c, _)| c.iter_outlives()) - .for_each(|c| each_edge(c.sub, c.sup)) + .for_each(|Constraint { kind: _, sub, sup, visible_for_leak_check }| { + each_edge(sub, sup, visible_for_leak_check) + }) } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 38b87eb7a9863..03bcb5215ee1a 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -115,10 +115,11 @@ pub enum ConstraintKind { #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub struct Constraint<'tcx> { pub kind: ConstraintKind, - // If `kind` is `VarSubVar` or `VarSubReg`, this must be a `ReVar`. + // If `kind` is `VarSubVar`, `VarSubReg`, `VarEqVar` or `VarEqReg`, this must be a `ReVar`. pub sub: Region<'tcx>, - // If `kind` is `VarSubVar` or `RegSubVar`, this must be a `ReVar`. + // If `kind` is `VarSubVar`, `RegSubVar` or `VarEqVar`, this must be a `ReVar`. pub sup: Region<'tcx>, + pub visible_for_leak_check: ty::VisibleForLeakCheck, } impl Constraint<'_> { @@ -127,7 +128,7 @@ impl Constraint<'_> { } pub fn iter_outlives(self) -> impl Iterator { - let Constraint { kind, sub, sup } = self; + let Constraint { kind, sub, sup, visible_for_leak_check } = self; match kind { ConstraintKind::VarSubVar @@ -135,18 +136,42 @@ impl Constraint<'_> { | ConstraintKind::VarSubReg | ConstraintKind::RegSubReg => iter::once(self).chain(None), - ConstraintKind::VarEqVar => { - iter::once(Constraint { kind: ConstraintKind::VarSubVar, sub, sup }) - .chain(Some(Constraint { kind: ConstraintKind::VarSubVar, sub: sup, sup: sub })) - } - ConstraintKind::VarEqReg => { - iter::once(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }) - .chain(Some(Constraint { kind: ConstraintKind::RegSubVar, sub: sup, sup: sub })) - } - ConstraintKind::RegEqReg => { - iter::once(Constraint { kind: ConstraintKind::RegSubReg, sub, sup }) - .chain(Some(Constraint { kind: ConstraintKind::RegSubReg, sub: sup, sup: sub })) - } + ConstraintKind::VarEqVar => iter::once(Constraint { + kind: ConstraintKind::VarSubVar, + sub, + sup, + visible_for_leak_check, + }) + .chain(Some(Constraint { + kind: ConstraintKind::VarSubVar, + sub: sup, + sup: sub, + visible_for_leak_check, + })), + ConstraintKind::VarEqReg => iter::once(Constraint { + kind: ConstraintKind::VarSubReg, + sub, + sup, + visible_for_leak_check, + }) + .chain(Some(Constraint { + kind: ConstraintKind::RegSubVar, + sub: sup, + sup: sub, + visible_for_leak_check, + })), + ConstraintKind::RegEqReg => iter::once(Constraint { + kind: ConstraintKind::RegSubReg, + sub, + sup, + visible_for_leak_check, + }) + .chain(Some(Constraint { + kind: ConstraintKind::RegSubReg, + sub: sup, + sup: sub, + visible_for_leak_check, + })), } } } @@ -457,6 +482,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { origin: SubregionOrigin<'tcx>, a: Region<'tcx>, b: Region<'tcx>, + visible_for_leak_check: ty::VisibleForLeakCheck, ) { if a != b { // FIXME: We could only emit constraints if `unify_var_{var, value}` fails when @@ -467,7 +493,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } (ReVar(a_vid), ReVar(b_vid), _, _) => { self.add_constraint( - Constraint { kind: ConstraintKind::VarEqVar, sub: a, sup: b }, + Constraint { + kind: ConstraintKind::VarEqVar, + sub: a, + sup: b, + visible_for_leak_check, + }, origin, ); debug!("make_eqregion: unifying {:?} with {:?}", a_vid, b_vid); @@ -479,12 +510,22 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { if reg.is_static() { // all regions are subregions of static, so don't go bidirectional here self.add_constraint( - Constraint { kind: ConstraintKind::RegSubVar, sub: reg, sup: var }, + Constraint { + kind: ConstraintKind::RegSubVar, + sub: reg, + sup: var, + visible_for_leak_check, + }, origin, ); } else { self.add_constraint( - Constraint { kind: ConstraintKind::VarEqReg, sub: var, sup: reg }, + Constraint { + kind: ConstraintKind::VarEqReg, + sub: var, + sup: reg, + visible_for_leak_check, + }, origin, ); } @@ -500,13 +541,23 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { (ReStatic, _, st, reg) | (_, ReStatic, reg, st) => { // all regions are subregions of static, so don't go bidirectional here self.add_constraint( - Constraint { kind: ConstraintKind::RegSubReg, sub: st, sup: reg }, + Constraint { + kind: ConstraintKind::RegSubReg, + sub: st, + sup: reg, + visible_for_leak_check, + }, origin, ); } _ => { self.add_constraint( - Constraint { kind: ConstraintKind::RegEqReg, sub: a, sup: b }, + Constraint { + kind: ConstraintKind::RegEqReg, + sub: a, + sup: b, + visible_for_leak_check, + }, origin, ); } @@ -520,6 +571,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, + visible_for_leak_check: ty::VisibleForLeakCheck, ) { // cannot add constraints once regions are resolved debug!("origin = {:#?}", origin); @@ -534,19 +586,33 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { (ReVar(sub_id), ReVar(sup_id)) => { if sub_id != sup_id { self.add_constraint( - Constraint { kind: ConstraintKind::VarSubVar, sub, sup }, + Constraint { + kind: ConstraintKind::VarSubVar, + sub, + sup, + visible_for_leak_check, + }, origin, ); } } - (_, ReVar(_)) => self - .add_constraint(Constraint { kind: ConstraintKind::RegSubVar, sub, sup }, origin), - (ReVar(_), _) => self - .add_constraint(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }, origin), + (_, ReVar(_)) => self.add_constraint( + Constraint { kind: ConstraintKind::RegSubVar, sub, sup, visible_for_leak_check }, + origin, + ), + (ReVar(_), _) => self.add_constraint( + Constraint { kind: ConstraintKind::VarSubReg, sub, sup, visible_for_leak_check }, + origin, + ), _ => { if sub != sup { self.add_constraint( - Constraint { kind: ConstraintKind::RegSubReg, sub, sup }, + Constraint { + kind: ConstraintKind::RegSubReg, + sub, + sup, + visible_for_leak_check, + }, origin, ) } @@ -655,8 +721,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { let new_r = ty::Region::new_var(tcx, c); for old_r in [a, b] { match t { - Glb => self.make_subregion(origin.clone(), new_r, old_r), - Lub => self.make_subregion(origin.clone(), old_r, new_r), + Glb => { + self.make_subregion(origin.clone(), new_r, old_r, ty::VisibleForLeakCheck::Yes) + } + Lub => { + self.make_subregion(origin.clone(), old_r, new_r, ty::VisibleForLeakCheck::Yes) + } } } debug!("combine_vars() c={:?}", c); diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 408e2a055f1ef..595392fcfb524 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -223,26 +223,29 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, 'tcx> { match self.ambient_variance { // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) ty::Covariant => { - self.infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_subregion(origin, b, a); + self.infcx.inner.borrow_mut().unwrap_region_constraints().make_subregion( + origin, + b, + a, + ty::VisibleForLeakCheck::Yes, + ); } // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) ty::Contravariant => { - self.infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_subregion(origin, a, b); + self.infcx.inner.borrow_mut().unwrap_region_constraints().make_subregion( + origin, + a, + b, + ty::VisibleForLeakCheck::Yes, + ); } ty::Invariant => { - self.infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_eqregion(origin, a, b); + self.infcx.inner.borrow_mut().unwrap_region_constraints().make_eqregion( + origin, + a, + b, + ty::VisibleForLeakCheck::Yes, + ); } ty::Bivariant => { unreachable!("Expected bivariance to be handled in relate_with_variance") diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 033e3e36b0247..c94acde0355a5 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -135,7 +135,8 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -pub type QueryRegionConstraint<'tcx> = (ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>); +pub type QueryRegionConstraint<'tcx> = + (ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>, ty::VisibleForLeakCheck); #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d8303a671c4a5..28490a1e94100 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -64,7 +64,7 @@ pub use rustc_type_ir::fast_reject::DeepRejectCtxt; )] use rustc_type_ir::inherent; pub use rustc_type_ir::relate::VarianceDiagInfo; -pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind}; +pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleForLeakCheck}; pub use rustc_type_ir::*; #[allow(hidden_glob_reexports, unused_imports)] use rustc_type_ir::{InferCtxtLike, Interner}; diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 0a3672343e33c..824c78094a69b 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -410,6 +410,11 @@ impl, I: Interner> TypeFolder for Canonicaliz } fn fold_region(&mut self, r: I::Region) -> I::Region { + // We canonicalize free regions from the input into placeholder regions so that + // region constraints created in nested contexts can be propagated back to the + // caller, instead of unifying them. + // See the following Zulip discussion for details: + // https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/A.20question.20on.20.23251/near/579240238 let kind = match r.kind() { ty::ReBound(..) => return r, @@ -417,7 +422,10 @@ impl, I: Interner> TypeFolder for Canonicaliz // when checking whether a `ParamEnv` candidate is global. ty::ReStatic => match self.canonicalize_mode { CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { - CanonicalVarKind::Region(ty::UniverseIndex::ROOT) + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon( + ty::UniverseIndex::ROOT, + self.variables.len().into(), + )) } CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) | CanonicalizeMode::Response { .. } => return r, @@ -431,24 +439,41 @@ impl, I: Interner> TypeFolder for Canonicaliz // `ReErased`. We may be able to short-circuit registering region // obligations if we encounter a `ReErased` on one side, for example. ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { - CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input(_) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon( + ty::UniverseIndex::ROOT, + self.variables.len().into(), + )) + } CanonicalizeMode::Response { .. } => return r, }, ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode { - CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input(_) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon( + ty::UniverseIndex::ROOT, + self.variables.len().into(), + )) + } CanonicalizeMode::Response { .. } => { panic!("unexpected region in response: {r:?}") } }, ty::RePlaceholder(placeholder) => match self.canonicalize_mode { - // We canonicalize placeholder regions as existentials in query inputs. - CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input(_) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon( + ty::UniverseIndex::ROOT, + self.variables.len().into(), + )) + } CanonicalizeMode::Response { max_input_universe } => { // If we have a placeholder region inside of a query, it must be from - // a new universe. - if max_input_universe.can_name(placeholder.universe()) { + // a new universe, unless from the root universe, which is used for + // canonicalization of any free region from the input. + if placeholder.universe() != ty::UniverseIndex::ROOT + && max_input_universe.can_name(placeholder.universe()) + { panic!("new placeholder in universe {max_input_universe:?}: {r:?}"); } CanonicalVarKind::PlaceholderRegion(placeholder) @@ -462,7 +487,12 @@ impl, I: Interner> TypeFolder for Canonicaliz "region vid should have been resolved fully before canonicalization" ); match self.canonicalize_mode { - CanonicalizeMode::Input(_) => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input(_) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new_anon( + ty::UniverseIndex::ROOT, + self.variables.len().into(), + )) + } CanonicalizeMode::Response { .. } => { CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) } diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index a32a693a899cf..4be7a45055785 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -25,7 +25,7 @@ use crate::delegate::SolverDelegate; use crate::resolve::eager_resolve_vars; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, - NestedNormalizationGoals, QueryInput, Response, inspect, + NestedNormalizationGoals, QueryInput, Response, VisibleForLeakCheck, inspect, }; pub mod canonicalizer; @@ -99,6 +99,7 @@ pub(super) fn instantiate_and_apply_query_response( param_env: I::ParamEnv, original_values: &[I::GenericArg], response: CanonicalResponse, + visible_for_leak_check: VisibleForLeakCheck, span: I::Span, ) -> (NestedNormalizationGoals, Certainty) where @@ -116,7 +117,11 @@ where let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = &*external_constraints; - register_region_constraints(delegate, region_constraints, span); + register_region_constraints( + delegate, + region_constraints.iter().map(|(c, vis)| (*c, vis.and(visible_for_leak_check))), + span, + ); register_new_opaque_types(delegate, opaque_types, span); (normalization_nested_goals.clone(), certainty) @@ -211,6 +216,16 @@ where } else { // For placeholders which were already part of the input, we simply map this // universal bound variable back the placeholder of the input. + // + // For `CanonicalVarKind::PlaceholderRegion`, this differs slightly: we + // canonicalize all free regions from the input into placeholders. This is + // unlike types or consts, where only input placeholders remain placeholders + // in the canonical form. However, we can still map these back to the original + // input regions, as we set their placeholder indices during canonicalization + // with there indices in the original values. We deliberately do so because + // we don't want to unify any free region into other region in nest contexts + // but want to propagate region constraints on them back to the caller. + // Therefore, we need to map them back to their original values. original_values[kind.expect_placeholder_index()] } }) @@ -250,21 +265,21 @@ fn unify_query_var_values( fn register_region_constraints( delegate: &D, - constraints: &[ty::RegionConstraint], + constraints: impl IntoIterator, VisibleForLeakCheck)>, span: I::Span, ) where D: SolverDelegate, I: Interner, { - for &constraint in constraints { + for (constraint, vis) in constraints { match constraint { ty::RegionConstraint::Outlives(ty::OutlivesPredicate(lhs, rhs)) => match lhs.kind() { - ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, span), - ty::GenericArgKind::Type(lhs) => delegate.register_ty_outlives(lhs, rhs, span), + ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, vis, span), + ty::GenericArgKind::Type(lhs) => delegate.register_ty_outlives(lhs, rhs, vis, span), ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"), }, ty::RegionConstraint::Eq(ty::RegionEqPredicate(lhs, rhs)) => { - delegate.equate_regions(lhs, rhs, span) + delegate.equate_regions(lhs, rhs, vis, span) } } } diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 7cf4e8a9238a5..541276f5925da 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,6 +1,6 @@ use std::ops::Deref; -use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; +use rustc_type_ir::solve::{Certainty, Goal, NoSolution, VisibleForLeakCheck}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable}; pub trait SolverDelegate: Deref + Sized { @@ -45,7 +45,9 @@ pub trait SolverDelegate: Deref + Sized { term: ::Term, ) -> Option::Predicate>>>; - fn make_deduplicated_region_constraints(&self) -> Vec>; + fn make_deduplicated_region_constraints( + &self, + ) -> Vec<(ty::RegionConstraint, VisibleForLeakCheck)>; fn instantiate_canonical( &self, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index e224febd3c927..68e973e7243ef 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -30,7 +30,8 @@ use crate::solve::ty::may_use_unstable_feature; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalSource, GoalStalledOn, HasChanged, MaybeCause, - NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, inspect, + NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, VisibleForLeakCheck, + inspect, }; mod probe; @@ -202,7 +203,7 @@ where stalled_on: Option>, ) -> Result, NoSolution> { EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| { - ecx.evaluate_goal(GoalSource::Misc, goal, stalled_on) + ecx.evaluate_goal(GoalSource::Misc, goal, stalled_on, true) }) } @@ -213,7 +214,7 @@ where ) -> bool { self.probe(|| { EvalCtxt::enter_root(self, self.cx().recursion_limit(), I::Span::dummy(), |ecx| { - ecx.evaluate_goal(GoalSource::Misc, goal, None) + ecx.evaluate_goal(GoalSource::Misc, goal, None, true) }) .is_ok_and(|r| match r.certainty { Certainty::Yes => true, @@ -232,7 +233,7 @@ where ) -> bool { self.probe(|| { EvalCtxt::enter_root(self, root_depth, I::Span::dummy(), |ecx| { - ecx.evaluate_goal(GoalSource::Misc, goal, None) + ecx.evaluate_goal(GoalSource::Misc, goal, None, true) }) }) .is_ok() @@ -413,9 +414,10 @@ where source: GoalSource, goal: Goal, stalled_on: Option>, + is_root_goal: bool, ) -> Result, NoSolution> { let (normalization_nested_goals, goal_evaluation) = - self.evaluate_goal_raw(source, goal, stalled_on)?; + self.evaluate_goal_raw(source, goal, stalled_on, is_root_goal)?; assert!(normalization_nested_goals.is_empty()); Ok(goal_evaluation) } @@ -432,6 +434,7 @@ where source: GoalSource, goal: Goal, stalled_on: Option>, + is_root_goal: bool, ) -> Result<(NestedNormalizationGoals, GoalEvaluation), NoSolution> { // If we have run this goal before, and it was stalled, check that any of the goal's // args have changed. Otherwise, we don't need to re-run the goal because it'll remain @@ -480,11 +483,33 @@ where let has_changed = if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; + // FIXME: We should revisit and consider removing this after + // *assumptions on binders* is available, like once we had done in the + // stabilization of `-Znext-solver=coherence`(#121848). + // We ignore constraints from the nested goals in leak check. This is to match + // with the old solver's behavior, which has separated evaluation and fulfillment, + // and the former doesn't consider outlives obligations from the later. + let vis = if is_root_goal { + VisibleForLeakCheck::Yes + } else { + match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(_) + | ty::PredicateKind::DynCompatible(_) + | ty::PredicateKind::Subtype(_) + | ty::PredicateKind::Coerce(_) + | ty::PredicateKind::ConstEquate(_, _) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::NormalizesTo(_) => VisibleForLeakCheck::No, + ty::PredicateKind::AliasRelate(_, _, _) => VisibleForLeakCheck::Yes, + } + }; + let (normalization_nested_goals, certainty) = instantiate_and_apply_query_response( self.delegate, goal.param_env, &orig_values, response, + vis, self.origin_span, ); @@ -676,7 +701,7 @@ where let ( NestedNormalizationGoals(nested_goals), GoalEvaluation { goal, certainty, stalled_on, has_changed: _ }, - ) = self.evaluate_goal_raw(source, unconstrained_goal, stalled_on)?; + ) = self.evaluate_goal_raw(source, unconstrained_goal, stalled_on, false)?; // Add the nested goals from normalization to our own nested goals. trace!(?nested_goals); self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None))); @@ -729,7 +754,7 @@ where } } else { let GoalEvaluation { goal, certainty, has_changed, stalled_on } = - self.evaluate_goal(source, goal, stalled_on)?; + self.evaluate_goal(source, goal, stalled_on, false)?; if has_changed == HasChanged::Yes { unchanged_certainty = None; } @@ -1092,13 +1117,18 @@ where args } - pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) { - self.delegate.register_ty_outlives(ty, lt, self.origin_span); + pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region, vis: VisibleForLeakCheck) { + self.delegate.register_ty_outlives(ty, lt, vis, self.origin_span); } - pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { + pub(super) fn register_region_outlives( + &self, + a: I::Region, + b: I::Region, + vis: VisibleForLeakCheck, + ) { // `'a: 'b` ==> `'b <= 'a` - self.delegate.sub_regions(b, a, self.origin_span); + self.delegate.sub_regions(b, a, vis, self.origin_span); } /// Computes the list of goals required for `arg` to be well-formed @@ -1296,7 +1326,7 @@ where let mut unique = HashSet::default(); external_constraints .region_constraints - .retain(|outlives| !outlives.is_trivial() && unique.insert(*outlives)); + .retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives)); let canonical = canonicalize_response( self.delegate, @@ -1527,6 +1557,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, goal.param_env, &proof_tree.orig_values, response, + VisibleForLeakCheck::Yes, origin_span, ); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 793d45f22d39b..ce58a300d9555 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -91,7 +91,7 @@ where goal: Goal>, ) -> QueryResult { let ty::OutlivesPredicate(ty, lt) = goal.predicate; - self.register_ty_outlives(ty, lt); + self.register_ty_outlives(ty, lt, VisibleForLeakCheck::Yes); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -101,7 +101,7 @@ where goal: Goal>, ) -> QueryResult { let ty::OutlivesPredicate(a, b) = goal.predicate; - self.register_region_outlives(a, b); + self.register_region_outlives(a, b, VisibleForLeakCheck::Yes); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 05ecc4725a7b6..bacdf8e9c64db 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -112,6 +112,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< SubregionOrigin::RelateRegionParamBound(span, None), outlives.1, outlives.0, + ty::VisibleForLeakCheck::Yes, ); Some(Certainty::Yes) } @@ -119,6 +120,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< self.0.register_type_outlives_constraint( outlives.0, outlives.1, + ty::VisibleForLeakCheck::Yes, &ObligationCause::dummy_with_span(span), ); @@ -204,7 +206,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn make_deduplicated_region_constraints(&self) -> Vec> { + fn make_deduplicated_region_constraints( + &self, + ) -> Vec<(ty::RegionConstraint<'tcx>, ty::VisibleForLeakCheck)> { // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.0.inner.borrow().region_obligations().to_owned(); @@ -221,8 +225,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< region_constraints .constraints .into_iter() - .filter(|&(outlives, _)| seen.insert(outlives)) - .map(|(outlives, _)| outlives) + .filter(|&(outlives, _, vis)| seen.insert((outlives, vis))) + .map(|(outlives, _, vis)| (outlives, vis)) .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f28e6f32b5f86..c337def9f0eb0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -738,7 +738,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); selcx.infcx.enter_forall(binder, |pred| { - selcx.infcx.register_region_outlives_constraint(pred, &dummy_cause); + selcx.infcx.register_region_outlives_constraint(pred, ty::VisibleForLeakCheck::Yes,&dummy_cause); }); } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { @@ -751,6 +751,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { selcx.infcx.register_type_outlives_constraint( t_a, selcx.infcx.tcx.lifetimes.re_static, + ty::VisibleForLeakCheck::Yes, &dummy_cause, ); } @@ -758,6 +759,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { selcx.infcx.register_type_outlives_constraint( t_a, r_b, + ty::VisibleForLeakCheck::Yes, &dummy_cause, ); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 11ff9911469e1..eed36605a34af 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -459,7 +459,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { - infcx.register_region_outlives_constraint(data, &obligation.cause); + infcx.register_region_outlives_constraint( + data, + ty::VisibleForLeakCheck::Yes, + &obligation.cause, + ); } ProcessResult::Changed(Default::default()) @@ -470,7 +474,12 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { r_b, ))) => { if infcx.considering_regions { - infcx.register_type_outlives_constraint(t_a, r_b, &obligation.cause); + infcx.register_type_outlives_constraint( + t_a, + r_b, + ty::VisibleForLeakCheck::Yes, + &obligation.cause, + ); } ProcessResult::Changed(Default::default()) } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 8bbdc9d76c514..8be26fed0ca42 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -83,13 +83,13 @@ fn implied_outlives_bounds<'a, 'tcx>( // outlives bound required proving some higher-ranked coroutine obl. let QueryRegionConstraints { constraints, assumptions: _ } = constraints; let cause = ObligationCause::misc(span, body_id); - for &(constraint, _) in &constraints { + for &(constraint, _, vis) in &constraints { match constraint { ty::RegionConstraint::Outlives(predicate) => { - infcx.register_outlives_constraint(predicate, &cause) + infcx.register_outlives_constraint(predicate, vis, &cause) } ty::RegionConstraint::Eq(predicate) => { - infcx.register_region_eq_constraint(predicate, &cause) + infcx.register_region_eq_constraint(predicate, vis, &cause) } } } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 0dd4ea823c949..83a77f17b28ce 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -80,7 +80,7 @@ fn compute_assumptions<'tcx>( tcx.mk_outlives_from_iter( constraints .into_iter() - .flat_map(|(constraint, _)| constraint.iter_outlives()) + .flat_map(|(constraint, _, _)| constraint.iter_outlives()) // FIXME(higher_ranked_auto): We probably should deeply resolve these before // filtering out infers which only correspond to unconstrained infer regions // which we can sometimes get. diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 905b005cd48f8..5581b70fcec4d 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -8,6 +8,7 @@ use crate::fold::TypeFoldable; use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; +use crate::solve::VisibleForLeakCheck; use crate::{self as ty, Interner, TyVid}; /// The current typing mode of an inference context. We unfortunately have some @@ -323,6 +324,7 @@ pub trait InferCtxtLike: Sized { &self, sub: ::Region, sup: ::Region, + vis: VisibleForLeakCheck, span: ::Span, ); @@ -330,6 +332,7 @@ pub trait InferCtxtLike: Sized { &self, a: ::Region, b: ::Region, + vis: VisibleForLeakCheck, span: ::Span, ); @@ -337,6 +340,7 @@ pub trait InferCtxtLike: Sized { &self, ty: ::Ty, r: ::Region, + vis: VisibleForLeakCheck, span: ::Span, ); diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 9064f13eb45e9..857738d207b4f 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -58,6 +58,7 @@ TrivialTypeTraversalImpls! { crate::solve::BuiltinImplSource, crate::solve::Certainty, crate::solve::GoalSource, + crate::solve::VisibleForLeakCheck, rustc_ast_ir::Mutability, // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 82ee4f75fcb0a..a643d22c17643 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -4,7 +4,7 @@ use self::combine::{PredicateEmittingRelation, super_combine_consts, super_combi use crate::data_structures::DelayedSet; use crate::relate::combine::combine_ty_args; pub use crate::relate::*; -use crate::solve::Goal; +use crate::solve::{Goal, VisibleForLeakCheck}; use crate::{self as ty, InferCtxtLike, Interner}; pub trait RelateExt: InferCtxtLike { @@ -256,10 +256,10 @@ where fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult { match self.ambient_variance { // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) - ty::Covariant => self.infcx.sub_regions(b, a, self.span), + ty::Covariant => self.infcx.sub_regions(b, a, VisibleForLeakCheck::Yes, self.span), // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) - ty::Contravariant => self.infcx.sub_regions(a, b, self.span), - ty::Invariant => self.infcx.equate_regions(a, b, self.span), + ty::Contravariant => self.infcx.sub_regions(a, b, VisibleForLeakCheck::Yes, self.span), + ty::Invariant => self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes, self.span), ty::Bivariant => { unreachable!("Expected bivariance to be handled in relate_with_variance") } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index fe779b66dc245..7f2575d0f4f79 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -253,7 +253,7 @@ impl Eq for Response {} #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct ExternalConstraintsData { - pub region_constraints: Vec>, + pub region_constraints: Vec<(ty::RegionConstraint, VisibleForLeakCheck)>, pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, pub normalization_nested_goals: NestedNormalizationGoals, } @@ -268,6 +268,25 @@ impl ExternalConstraintsData { } } +/// Whether the given region constraint should be considered/ignored for +/// leak check. In most part of the compiler, this should be `Yes`, except +/// for applying constraints from the nested goals in next-solver. +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub enum VisibleForLeakCheck { + Yes, + No, +} + +impl VisibleForLeakCheck { + pub fn and(self, other: VisibleForLeakCheck) -> VisibleForLeakCheck { + match (self, other) { + (VisibleForLeakCheck::Yes, VisibleForLeakCheck::Yes) => VisibleForLeakCheck::Yes, + (VisibleForLeakCheck::No, _) | (_, VisibleForLeakCheck::No) => VisibleForLeakCheck::No, + } + } +} + #[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] diff --git a/tests/crashes/140577.rs b/tests/crashes/140577.rs deleted file mode 100644 index 21e6b1e1522fb..0000000000000 --- a/tests/crashes/140577.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ known-bug: #140577 -//@ compile-flags: -Znext-solver=globally -//@ edition:2021 - -use std::future::Future; -use std::pin::Pin; -trait Acquire { - type Connection; -} -impl Acquire for &'static () { - type Connection = (); -} -fn b() -> impl Future + Send { - let x: Pin + Send>> = todo!(); - x -} -fn main() { - async { - b::<&()>().await; - } - .aa(); -} - -impl Filter for F where F: Send {} - -trait Filter { - fn aa(self) - where - Self: Sized, - { - } -} diff --git a/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr b/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr index ab51e2bdae77f..27418eb05dc7d 100644 --- a/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr +++ b/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr @@ -2,12 +2,10 @@ error[E0308]: mismatched types --> $DIR/must-prove-where-clauses-on-norm.rs:23:61 | LL | let func: for<'a, 'b> fn((), &'b str) -> &'static str = foo::<()>; - | ------------------------------------------- ^^^^^^^^^ one type is more general than the other - | | - | expected due to this + | ^^^^^^^^^ one type is more general than the other | - = note: expected fn pointer `for<'b> fn((), &'b _) -> &'static _` - found fn item `for<'b> fn(<() as Trait>::Assoc<'_, 'b>, &'b _) -> &_ {foo::<'_, ()>}` + = note: expected fn pointer `for<'b> fn((), &'b _) -> &_` + found fn pointer `for<'b> fn((), &'b _) -> &_` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr index ddfc94da1354c..dcf0ed0931995 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -1,14 +1,8 @@ -error[E0271]: type mismatch resolving `>::Assoc == usize` - --> $DIR/candidate-from-env-universe-err-project.rs:38:24 +error: higher-ranked subtype error + --> $DIR/candidate-from-env-universe-err-project.rs:38:5 | LL | projection_bound::(); - | ^ types differ - | -note: required by a bound in `projection_bound` - --> $DIR/candidate-from-env-universe-err-project.rs:19:42 - | -LL | fn projection_bound Trait<'a, Assoc = usize>>() {} - | ^^^^^^^^^^^^^ required by this bound in `projection_bound` + | ^^^^^^^^^^^^^^^^^^^^^ error: higher-ranked subtype error --> $DIR/candidate-from-env-universe-err-project.rs:52:30 @@ -26,4 +20,3 @@ LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs index dd6da62a47272..2dce218f5b83b 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs @@ -36,7 +36,7 @@ fn function2>() { // does not use the leak check when trying the where-bound, causing us // to prefer it over the impl, resulting in a placeholder error. projection_bound::(); - //[next]~^ ERROR type mismatch resolving `>::Assoc == usize` + //[next]~^ ERROR higher-ranked subtype error //[current]~^^ ERROR mismatched types } diff --git a/tests/ui/implied-bounds/normalization-preserve-equality.borrowck.stderr b/tests/ui/implied-bounds/normalization-preserve-equality.borrowck_current.stderr similarity index 90% rename from tests/ui/implied-bounds/normalization-preserve-equality.borrowck.stderr rename to tests/ui/implied-bounds/normalization-preserve-equality.borrowck_current.stderr index 96c76ca9ac311..fae1838b32fca 100644 --- a/tests/ui/implied-bounds/normalization-preserve-equality.borrowck.stderr +++ b/tests/ui/implied-bounds/normalization-preserve-equality.borrowck_current.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/normalization-preserve-equality.rs:24:1 + --> $DIR/normalization-preserve-equality.rs:27:1 | LL | fn test_borrowck<'a, 'b>(_: ( as Trait>::Ty, Equal<'a, 'b>)) { | ^^^^^^^^^^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | fn test_borrowck<'a, 'b>(_: ( as Trait>::Ty, Equal<'a, 'b>)) = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/normalization-preserve-equality.rs:24:1 + --> $DIR/normalization-preserve-equality.rs:27:1 | LL | fn test_borrowck<'a, 'b>(_: ( as Trait>::Ty, Equal<'a, 'b>)) { | ^^^^^^^^^^^^^^^^^--^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/implied-bounds/normalization-preserve-equality.rs b/tests/ui/implied-bounds/normalization-preserve-equality.rs index 712c8ce945df0..0d50d26b0488b 100644 --- a/tests/ui/implied-bounds/normalization-preserve-equality.rs +++ b/tests/ui/implied-bounds/normalization-preserve-equality.rs @@ -1,9 +1,12 @@ -// Both revisions should pass. `borrowck` revision is a bug! +// All the revisions should pass. `borrowck_current` revision is a bug! // -//@ revisions: wfcheck borrowck +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ revisions: wfcheck borrowck_current borrowck_next //@ [wfcheck] check-pass -//@ [borrowck] check-fail -//@ [borrowck] known-bug: #106569 +//@ [borrowck_current] check-fail +//@ [borrowck_current] known-bug: #106569 +//@ [borrowck_next] compile-flags: -Znext-solver +//@ [borrowck_next] check-pass struct Equal<'a, 'b>(&'a &'b (), &'b &'a ()); // implies 'a == 'b @@ -20,7 +23,7 @@ trait WfCheckTrait {} #[cfg(wfcheck)] impl<'a, 'b> WfCheckTrait for ( as Trait>::Ty, Equal<'a, 'b>) {} -#[cfg(borrowck)] +#[cfg(any(borrowck_current, borrowck_next))] fn test_borrowck<'a, 'b>(_: ( as Trait>::Ty, Equal<'a, 'b>)) { let _ = None::>; } diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs new file mode 100644 index 0000000000000..7c20246e5eb71 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs @@ -0,0 +1,43 @@ +//@ check-pass +//@ compile-flags: -Znext-solver=globally +//@ edition:2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed coroutine +// hidden type failing the leak check in the next-solver. +// +// In `TypingMode::Analysis`, the problematic type is hidden behind a +// stalled coroutine candidate. However, in later passes (e.g. MIR +// validation), we eagerly normalize it. The candidate that was +// previously accepted as a solution then fails the leak check, resulting +// in broken MIR and ultimately an ICE. + +use std::future::Future; +use std::pin::Pin; +trait Acquire { + type Connection; +} +impl Acquire for &'static () { + type Connection = (); +} +fn b() -> impl Future + Send { + let x: Pin + Send>> = todo!(); + x +} +fn main() { + async { + b::<&()>().await; + } + .aa(); +} + +impl Filter for F where F: Send {} + +trait Filter { + fn aa(self) + where + Self: Sized, + { + } +} diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs new file mode 100644 index 0000000000000..004775b822976 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs @@ -0,0 +1,48 @@ +//@ check-pass +//@ compile-flags: -Znext-solver -Zvalidate-mir +//@ edition: 2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed coroutine +// hidden type failing the leak check in the next-solver. +// +// In `TypingMode::Analysis`, the problematic type is hidden behind a +// stalled coroutine candidate. However, in later passes (e.g. MIR +// validation), we eagerly normalize it. The candidate that was +// previously accepted as a solution then fails the leak check, resulting +// in broken MIR and ultimately an ICE. + +use std::future::Future; + +trait Access { + // has to have an associated type, but can be anything + type Reader; + + fn read(&self) -> impl Future + Send { + async { loop {} } + } +} + +trait AccessDyn: Sync {} +impl Access for dyn AccessDyn { + type Reader = (); +} + +trait Stream { + fn poll_next(s: &'static dyn AccessDyn); +} + +// has to be a function in a trait impl, can't be a normal impl block or standalone fn +impl Stream for () { + fn poll_next(s: &'static dyn AccessDyn) { + // new async block is important + is_dyn_send(&async { + s.read().await; + }); + } +} + +fn is_dyn_send(_: &dyn Send) {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs new file mode 100644 index 0000000000000..7de6ec519eaa5 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs @@ -0,0 +1,34 @@ +//@ check-pass +//@ compile-flags: -Znext-solver +//@ edition:2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed coroutine +// hidden type failing the leak check in the next-solver. +// +// In `TypingMode::Analysis`, the problematic type is hidden behind a +// stalled coroutine candidate. However, in later passes (e.g. MIR +// validation), we eagerly normalize it. The candidate that was +// previously accepted as a solution then fails the leak check, resulting +// in broken MIR and ultimately an ICE. + +trait Trait { + type Assoc; +} +impl Trait for &'static u32 { + type Assoc = (); +} +struct W(T::Assoc); + +fn prove_send_and_hide(x: T) -> impl Send { x } +fn as_dyn_send(_: &dyn Send) {} +pub fn main() { + // Checking whether the cast to the trait object is correct + // during MIR validation uses `TypingMode::PostAnalysis` and + // therefore looks into the opaque. + as_dyn_send(&async move { + let opaque_ty = prove_send_and_hide(W::<&'static u32>(())); + std::future::ready(opaque_ty).await; + }); +} diff --git a/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs b/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs new file mode 100644 index 0000000000000..e071510976a14 --- /dev/null +++ b/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs @@ -0,0 +1,45 @@ +//@ run-pass + +// Regression test for . + +#![allow(warnings)] + +trait Trait { + type Assoc; +} +impl<'a, 'b: 'a> Trait for Inv<'a, 'b> { + type Assoc = (); +} + +trait ReqWf {} +impl ReqWf for T where T::Assoc: Sized {} +struct Inv<'a, 'b: 'a>(Option<*mut &'a &'b ()>); +fn mk_opaque<'a, 'b>(x: &'a &'b u32) -> impl ReqWf + use<'a, 'b> { + Inv::<'a, 'b>(None) +} + +trait Bound {} +impl Bound for F where F: FnOnce(T) -> R {} +trait ImpossiblePredicates { + fn call_me(&self) + where + F: for<'a, 'b> Bound<&'a &'b u32>, + { + println!("method body"); + } +} +impl ImpossiblePredicates for () {} +fn mk_trait_object(_: F) -> Box> { + Box::new(()) +} +pub fn main() { + let obj = mk_trait_object(mk_opaque); + // This previously caused a segfault: the where-bounds of + // `ImpossiblePredicate::call_me` did not hold due to missing implied bounds + // for the fully normalized opaque type of `obj` in `fn impossible_predicates`. + // As a result, the method's vtable ended up empty. + // + // However, earlier compilation passes did not report an error because the + // opaque type had not yet been fully normalized. + obj.call_me(); +}