Skip to content

Commit d3d5163

Browse files
authored
Rollup merge of rust-lang#108186 - compiler-errors:closures-with-late-bound-types-r-bad, r=cjgillot
Deny non-lifetime bound vars in `for<..> ||` closure binders Moves the check for illegal bound var types from astconv to resolve_bound_vars. If a binder is defined to have a type or const late-bound var that's not allowed, we'll resolve any usages to ty error or const error values, so we shouldn't ever see late-bound types or consts in places they aren't expected. Fixes rust-lang#108184 Fixes rust-lang#108181 Fixes rust-lang#108192
2 parents 7f9d9de + 5ec812d commit d3d5163

File tree

23 files changed

+210
-102
lines changed

23 files changed

+210
-102
lines changed

compiler/rustc_feature/src/active.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ declare_features! (
474474
/// Allows using the `non_exhaustive_omitted_patterns` lint.
475475
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
476476
/// Allows `for<T>` binders in where-clauses
477-
(incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(1), None),
477+
(incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(108185), None),
478478
/// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
479479
/// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
480480
/// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.

compiler/rustc_hir_analysis/src/astconv/mod.rs

+8-46
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
252252
// (*) -- not late-bound, won't change
253253
}
254254

255+
Some(rbv::ResolvedArg::Error(_)) => {
256+
bug!("only ty/ct should resolve as ResolvedArg::Error")
257+
}
258+
255259
None => {
256260
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
257261
debug!(?lifetime, "unelided lifetime in signature");
@@ -2689,6 +2693,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
26892693
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
26902694
tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
26912695
}
2696+
Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error_with_guaranteed(guar),
26922697
arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
26932698
}
26942699
}
@@ -2893,22 +2898,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
28932898
hir::TyKind::BareFn(bf) => {
28942899
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
28952900

2896-
let fn_ptr_ty = tcx.mk_fn_ptr(self.ty_of_fn(
2901+
tcx.mk_fn_ptr(self.ty_of_fn(
28972902
ast_ty.hir_id,
28982903
bf.unsafety,
28992904
bf.abi,
29002905
bf.decl,
29012906
None,
29022907
Some(ast_ty),
2903-
));
2904-
2905-
if let Some(guar) =
2906-
deny_non_region_late_bound(tcx, bf.generic_params, "function pointer")
2907-
{
2908-
tcx.ty_error_with_guaranteed(guar)
2909-
} else {
2910-
fn_ptr_ty
2911-
}
2908+
))
29122909
}
29132910
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
29142911
self.maybe_lint_bare_trait(ast_ty, in_path);
@@ -2917,21 +2914,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29172914
TraitObjectSyntax::DynStar => ty::DynStar,
29182915
};
29192916

2920-
let object_ty = self.conv_object_ty_poly_trait_ref(
2921-
ast_ty.span,
2922-
bounds,
2923-
lifetime,
2924-
borrowed,
2925-
repr,
2926-
);
2927-
2928-
if let Some(guar) = bounds.iter().find_map(|trait_ref| {
2929-
deny_non_region_late_bound(tcx, trait_ref.bound_generic_params, "trait object")
2930-
}) {
2931-
tcx.ty_error_with_guaranteed(guar)
2932-
} else {
2933-
object_ty
2934-
}
2917+
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
29352918
}
29362919
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
29372920
debug!(?maybe_qself, ?path);
@@ -3392,24 +3375,3 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
33923375
}
33933376
}
33943377
}
3395-
3396-
fn deny_non_region_late_bound(
3397-
tcx: TyCtxt<'_>,
3398-
params: &[hir::GenericParam<'_>],
3399-
where_: &str,
3400-
) -> Option<ErrorGuaranteed> {
3401-
params.iter().find_map(|bad_param| {
3402-
let what = match bad_param.kind {
3403-
hir::GenericParamKind::Type { .. } => "type",
3404-
hir::GenericParamKind::Const { .. } => "const",
3405-
hir::GenericParamKind::Lifetime { .. } => return None,
3406-
};
3407-
3408-
let mut diag = tcx.sess.struct_span_err(
3409-
bad_param.span,
3410-
format!("late-bound {what} parameter not allowed on {where_} types"),
3411-
);
3412-
3413-
Some(if tcx.features().non_lifetime_binders { diag.emit() } else { diag.delay_as_bug() })
3414-
})
3415-
}

compiler/rustc_hir_analysis/src/collect/generics_of.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
398398
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
399399
Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
400400
if debruijn < self.outer_index => {}
401-
Some(rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..)) | None => {
401+
Some(
402+
rbv::ResolvedArg::LateBound(..)
403+
| rbv::ResolvedArg::Free(..)
404+
| rbv::ResolvedArg::Error(_),
405+
)
406+
| None => {
402407
self.has_late_bound_regions = Some(lt.ident.span);
403408
}
404409
}

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+100-38
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl RegionExt for ResolvedArg {
5050

5151
fn id(&self) -> Option<DefId> {
5252
match *self {
53-
ResolvedArg::StaticLifetime => None,
53+
ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None,
5454

5555
ResolvedArg::EarlyBound(id)
5656
| ResolvedArg::LateBound(_, _, id)
@@ -336,7 +336,57 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
336336
}
337337
}
338338
}
339+
340+
fn visit_poly_trait_ref_inner(
341+
&mut self,
342+
trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
343+
non_lifetime_binder_allowed: NonLifetimeBinderAllowed,
344+
) {
345+
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
346+
347+
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
348+
349+
let initial_bound_vars = binders.len() as u32;
350+
let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
351+
let binders_iter =
352+
trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
353+
let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
354+
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
355+
bound_vars.insert(pair.0, pair.1);
356+
r
357+
});
358+
binders.extend(binders_iter);
359+
360+
if let NonLifetimeBinderAllowed::Deny(where_) = non_lifetime_binder_allowed {
361+
deny_non_region_late_bound(self.tcx, &mut bound_vars, where_);
362+
}
363+
364+
debug!(?binders);
365+
self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
366+
367+
// Always introduce a scope here, even if this is in a where clause and
368+
// we introduced the binders around the bounded Ty. In that case, we
369+
// just reuse the concatenation functionality also present in nested trait
370+
// refs.
371+
let scope = Scope::Binder {
372+
hir_id: trait_ref.trait_ref.hir_ref_id,
373+
bound_vars,
374+
s: self.scope,
375+
scope_type,
376+
where_bound_origin: None,
377+
};
378+
self.with(scope, |this| {
379+
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
380+
this.visit_trait_ref(&trait_ref.trait_ref);
381+
});
382+
}
383+
}
384+
385+
enum NonLifetimeBinderAllowed {
386+
Deny(&'static str),
387+
Allow,
339388
}
389+
340390
impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
341391
type NestedFilter = nested_filter::OnlyBodies;
342392

@@ -400,7 +450,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
400450
}
401451
}
402452

403-
let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
453+
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
404454
bound_generic_params
405455
.iter()
406456
.enumerate()
@@ -411,6 +461,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
411461
})
412462
.unzip();
413463

464+
deny_non_region_late_bound(self.tcx, &mut bound_vars, "closures");
465+
414466
self.record_late_bound_vars(e.hir_id, binders);
415467
let scope = Scope::Binder {
416468
hir_id: e.hir_id,
@@ -567,7 +619,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
567619
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
568620
match ty.kind {
569621
hir::TyKind::BareFn(c) => {
570-
let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
622+
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
571623
.generic_params
572624
.iter()
573625
.enumerate()
@@ -577,6 +629,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
577629
(pair, r)
578630
})
579631
.unzip();
632+
633+
deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types");
634+
580635
self.record_late_bound_vars(ty.hir_id, binders);
581636
let scope = Scope::Binder {
582637
hir_id: ty.hir_id,
@@ -596,7 +651,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
596651
let scope = Scope::TraitRefBoundary { s: self.scope };
597652
self.with(scope, |this| {
598653
for bound in bounds {
599-
this.visit_poly_trait_ref(bound);
654+
this.visit_poly_trait_ref_inner(
655+
bound,
656+
NonLifetimeBinderAllowed::Deny("trait object types"),
657+
);
600658
}
601659
});
602660
match lifetime.res {
@@ -967,39 +1025,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
9671025
}
9681026

9691027
fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
970-
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
971-
972-
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
973-
974-
let initial_bound_vars = binders.len() as u32;
975-
let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
976-
let binders_iter =
977-
trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
978-
let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
979-
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
980-
bound_vars.insert(pair.0, pair.1);
981-
r
982-
});
983-
binders.extend(binders_iter);
984-
985-
debug!(?binders);
986-
self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
987-
988-
// Always introduce a scope here, even if this is in a where clause and
989-
// we introduced the binders around the bounded Ty. In that case, we
990-
// just reuse the concatenation functionality also present in nested trait
991-
// refs.
992-
let scope = Scope::Binder {
993-
hir_id: trait_ref.trait_ref.hir_ref_id,
994-
bound_vars,
995-
s: self.scope,
996-
scope_type,
997-
where_bound_origin: None,
998-
};
999-
self.with(scope, |this| {
1000-
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
1001-
this.visit_trait_ref(&trait_ref.trait_ref);
1002-
});
1028+
self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
10031029
}
10041030
}
10051031

@@ -1364,7 +1390,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13641390
return;
13651391
}
13661392

1367-
span_bug!(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}",);
1393+
self.tcx
1394+
.sess
1395+
.delay_span_bug(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}");
13681396
}
13691397

13701398
#[instrument(level = "debug", skip(self))]
@@ -1915,3 +1943,37 @@ fn is_late_bound_map(
19151943
}
19161944
}
19171945
}
1946+
1947+
pub fn deny_non_region_late_bound(
1948+
tcx: TyCtxt<'_>,
1949+
bound_vars: &mut FxIndexMap<LocalDefId, ResolvedArg>,
1950+
where_: &str,
1951+
) {
1952+
let mut first = true;
1953+
1954+
for (var, arg) in bound_vars {
1955+
let Node::GenericParam(param) = tcx.hir().get_by_def_id(*var) else {
1956+
bug!();
1957+
};
1958+
1959+
let what = match param.kind {
1960+
hir::GenericParamKind::Type { .. } => "type",
1961+
hir::GenericParamKind::Const { .. } => "const",
1962+
hir::GenericParamKind::Lifetime { .. } => continue,
1963+
};
1964+
1965+
let mut diag = tcx.sess.struct_span_err(
1966+
param.span,
1967+
format!("late-bound {what} parameter not allowed on {where_}"),
1968+
);
1969+
1970+
let guar = if tcx.features().non_lifetime_binders && first {
1971+
diag.emit()
1972+
} else {
1973+
diag.delay_as_bug()
1974+
};
1975+
1976+
first = false;
1977+
*arg = ResolvedArg::Error(guar);
1978+
}
1979+
}

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
134134
rbv::ResolvedArg::StaticLifetime
135135
| rbv::ResolvedArg::Free(_, _)
136136
| rbv::ResolvedArg::EarlyBound(_)
137-
| rbv::ResolvedArg::LateBound(_, _, _),
137+
| rbv::ResolvedArg::LateBound(_, _, _)
138+
| rbv::ResolvedArg::Error(_),
138139
)
139140
| None,
140141
_,
@@ -211,7 +212,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
211212
rbv::ResolvedArg::StaticLifetime
212213
| rbv::ResolvedArg::EarlyBound(_)
213214
| rbv::ResolvedArg::LateBound(_, _, _)
214-
| rbv::ResolvedArg::Free(_, _),
215+
| rbv::ResolvedArg::Free(_, _)
216+
| rbv::ResolvedArg::Error(_),
215217
)
216218
| None,
217219
_,

compiler/rustc_middle/src/middle/resolve_bound_vars.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::ty;
44

55
use rustc_data_structures::fx::FxHashMap;
6+
use rustc_errors::ErrorGuaranteed;
67
use rustc_hir::def_id::DefId;
78
use rustc_hir::{ItemLocalId, OwnerId};
89
use rustc_macros::HashStable;
@@ -13,6 +14,7 @@ pub enum ResolvedArg {
1314
EarlyBound(/* decl */ DefId),
1415
LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId),
1516
Free(DefId, /* lifetime decl */ DefId),
17+
Error(ErrorGuaranteed),
1618
}
1719

1820
/// A set containing, at most, one known element.

compiler/rustc_middle/src/ty/consts.rs

+3
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ impl<'tcx> Const<'tcx> {
149149
ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)),
150150
ty,
151151
)),
152+
Some(rbv::ResolvedArg::Error(guar)) => {
153+
Some(tcx.const_error_with_guaranteed(ty, guar))
154+
}
152155
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id),
153156
}
154157
}

tests/ui/bounds-lifetime.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ error[E0658]: only lifetime parameters can be used in this context
2222
LL | type D = for<'a, T> fn();
2323
| ^
2424
|
25-
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
25+
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
2626
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
2727

2828
error[E0658]: only lifetime parameters can be used in this context
@@ -31,7 +31,7 @@ error[E0658]: only lifetime parameters can be used in this context
3131
LL | type E = dyn for<T> Fn();
3232
| ^
3333
|
34-
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
34+
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
3535
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
3636

3737
error: aborting due to 5 previous errors
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(closure_lifetime_binder, non_lifetime_binders)]
2+
//~^ WARN is incomplete and may not be safe to use
3+
4+
fn main() {
5+
for<const N: i32> || -> () {};
6+
//~^ ERROR late-bound const parameter not allowed on closures
7+
}

0 commit comments

Comments
 (0)