diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index abc33e84139fc..e1d269b828be4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -252,6 +252,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // (*) -- not late-bound, won't change } + Some(rbv::ResolvedArg::Error(_)) => { + bug!("only ty/ct should resolve as ResolvedArg::Error") + } + None => { self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| { debug!(?lifetime, "unelided lifetime in signature"); @@ -2689,6 +2693,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let index = generics.param_def_id_to_index[&def_id.to_def_id()]; tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)) } + Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error_with_guaranteed(guar), arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), } } @@ -2893,22 +2898,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TyKind::BareFn(bf) => { require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span); - let fn_ptr_ty = tcx.mk_fn_ptr(self.ty_of_fn( + tcx.mk_fn_ptr(self.ty_of_fn( ast_ty.hir_id, bf.unsafety, bf.abi, bf.decl, None, Some(ast_ty), - )); - - if let Some(guar) = - deny_non_region_late_bound(tcx, bf.generic_params, "function pointer") - { - tcx.ty_error_with_guaranteed(guar) - } else { - fn_ptr_ty - } + )) } hir::TyKind::TraitObject(bounds, lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); @@ -2917,21 +2914,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { TraitObjectSyntax::DynStar => ty::DynStar, }; - let object_ty = self.conv_object_ty_poly_trait_ref( - ast_ty.span, - bounds, - lifetime, - borrowed, - repr, - ); - - if let Some(guar) = bounds.iter().find_map(|trait_ref| { - deny_non_region_late_bound(tcx, trait_ref.bound_generic_params, "trait object") - }) { - tcx.ty_error_with_guaranteed(guar) - } else { - object_ty - } + self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); @@ -3392,24 +3375,3 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } } - -fn deny_non_region_late_bound( - tcx: TyCtxt<'_>, - params: &[hir::GenericParam<'_>], - where_: &str, -) -> Option { - params.iter().find_map(|bad_param| { - let what = match bad_param.kind { - hir::GenericParamKind::Type { .. } => "type", - hir::GenericParamKind::Const { .. } => "const", - hir::GenericParamKind::Lifetime { .. } => return None, - }; - - let mut diag = tcx.sess.struct_span_err( - bad_param.span, - format!("late-bound {what} parameter not allowed on {where_} types"), - ); - - Some(if tcx.features().non_lifetime_binders { diag.emit() } else { diag.delay_as_bug() }) - }) -} diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 7bcaeadbcf67b..127d4fa908bb9 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -398,7 +398,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option {} Some(rbv::ResolvedArg::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {} - Some(rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..)) | None => { + Some( + rbv::ResolvedArg::LateBound(..) + | rbv::ResolvedArg::Free(..) + | rbv::ResolvedArg::Error(_), + ) + | None => { self.has_late_bound_regions = Some(lt.ident.span); } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 8a110bfc2f7f5..c0c90e47a7539 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -50,7 +50,7 @@ impl RegionExt for ResolvedArg { fn id(&self) -> Option { match *self { - ResolvedArg::StaticLifetime => None, + ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None, ResolvedArg::EarlyBound(id) | ResolvedArg::LateBound(_, _, id) @@ -336,7 +336,57 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } } + + fn visit_poly_trait_ref_inner( + &mut self, + trait_ref: &'tcx hir::PolyTraitRef<'tcx>, + non_lifetime_binder_allowed: NonLifetimeBinderAllowed, + ) { + debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); + + let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); + + let initial_bound_vars = binders.len() as u32; + let mut bound_vars: FxIndexMap = FxIndexMap::default(); + let binders_iter = + trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| { + let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); + let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); + bound_vars.insert(pair.0, pair.1); + r + }); + binders.extend(binders_iter); + + if let NonLifetimeBinderAllowed::Deny(where_) = non_lifetime_binder_allowed { + deny_non_region_late_bound(self.tcx, &mut bound_vars, where_); + } + + debug!(?binders); + self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders); + + // Always introduce a scope here, even if this is in a where clause and + // we introduced the binders around the bounded Ty. In that case, we + // just reuse the concatenation functionality also present in nested trait + // refs. + let scope = Scope::Binder { + hir_id: trait_ref.trait_ref.hir_ref_id, + bound_vars, + s: self.scope, + scope_type, + where_bound_origin: None, + }; + self.with(scope, |this| { + walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); + this.visit_trait_ref(&trait_ref.trait_ref); + }); + } +} + +enum NonLifetimeBinderAllowed { + Deny(&'static str), + Allow, } + impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; @@ -400,7 +450,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } - let (bound_vars, binders): (FxIndexMap, Vec<_>) = + let (mut bound_vars, binders): (FxIndexMap, Vec<_>) = bound_generic_params .iter() .enumerate() @@ -411,6 +461,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }) .unzip(); + deny_non_region_late_bound(self.tcx, &mut bound_vars, "closures"); + self.record_late_bound_vars(e.hir_id, binders); let scope = Scope::Binder { hir_id: e.hir_id, @@ -567,7 +619,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { match ty.kind { hir::TyKind::BareFn(c) => { - let (bound_vars, binders): (FxIndexMap, Vec<_>) = c + let (mut bound_vars, binders): (FxIndexMap, Vec<_>) = c .generic_params .iter() .enumerate() @@ -577,6 +629,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { (pair, r) }) .unzip(); + + deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types"); + self.record_late_bound_vars(ty.hir_id, binders); let scope = Scope::Binder { hir_id: ty.hir_id, @@ -596,7 +651,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { for bound in bounds { - this.visit_poly_trait_ref(bound); + this.visit_poly_trait_ref_inner( + bound, + NonLifetimeBinderAllowed::Deny("trait object types"), + ); } }); match lifetime.res { @@ -967,39 +1025,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { - debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); - - let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); - - let initial_bound_vars = binders.len() as u32; - let mut bound_vars: FxIndexMap = FxIndexMap::default(); - let binders_iter = - trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| { - let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param); - let r = late_arg_as_bound_arg(self.tcx, &pair.1, param); - bound_vars.insert(pair.0, pair.1); - r - }); - binders.extend(binders_iter); - - debug!(?binders); - self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders); - - // Always introduce a scope here, even if this is in a where clause and - // we introduced the binders around the bounded Ty. In that case, we - // just reuse the concatenation functionality also present in nested trait - // refs. - let scope = Scope::Binder { - hir_id: trait_ref.trait_ref.hir_ref_id, - bound_vars, - s: self.scope, - scope_type, - where_bound_origin: None, - }; - self.with(scope, |this| { - walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); - this.visit_trait_ref(&trait_ref.trait_ref); - }); + self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow); } } @@ -1364,7 +1390,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { return; } - span_bug!(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}",); + self.tcx + .sess + .delay_span_bug(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}"); } #[instrument(level = "debug", skip(self))] @@ -1915,3 +1943,37 @@ fn is_late_bound_map( } } } + +pub fn deny_non_region_late_bound( + tcx: TyCtxt<'_>, + bound_vars: &mut FxIndexMap, + where_: &str, +) { + let mut first = true; + + for (var, arg) in bound_vars { + let Node::GenericParam(param) = tcx.hir().get_by_def_id(*var) else { + bug!(); + }; + + let what = match param.kind { + hir::GenericParamKind::Type { .. } => "type", + hir::GenericParamKind::Const { .. } => "const", + hir::GenericParamKind::Lifetime { .. } => continue, + }; + + let mut diag = tcx.sess.struct_span_err( + param.span, + format!("late-bound {what} parameter not allowed on {where_}"), + ); + + let guar = if tcx.features().non_lifetime_binders && first { + diag.emit() + } else { + diag.delay_as_bug() + }; + + first = false; + *arg = ResolvedArg::Error(guar); + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 4fe6c6618f698..fec04af231393 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -134,7 +134,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::Free(_, _) | rbv::ResolvedArg::EarlyBound(_) - | rbv::ResolvedArg::LateBound(_, _, _), + | rbv::ResolvedArg::LateBound(_, _, _) + | rbv::ResolvedArg::Error(_), ) | None, _, @@ -211,7 +212,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(_) | rbv::ResolvedArg::LateBound(_, _, _) - | rbv::ResolvedArg::Free(_, _), + | rbv::ResolvedArg::Free(_, _) + | rbv::ResolvedArg::Error(_), ) | None, _, diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index b96d07e7dc831..c59704fc0238f 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -3,6 +3,7 @@ use crate::ty; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_hir::{ItemLocalId, OwnerId}; use rustc_macros::HashStable; @@ -13,6 +14,7 @@ pub enum ResolvedArg { EarlyBound(/* decl */ DefId), LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId), Free(DefId, /* lifetime decl */ DefId), + Error(ErrorGuaranteed), } /// A set containing, at most, one known element. diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 08e2ef0cadab7..884ae7f5da284 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -149,6 +149,9 @@ impl<'tcx> Const<'tcx> { ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), ty, )), + Some(rbv::ResolvedArg::Error(guar)) => { + Some(tcx.const_error_with_guaranteed(ty, guar)) + } arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } } diff --git a/tests/ui/closures/binder/type-bound-2.rs b/tests/ui/closures/binder/type-bound-2.rs new file mode 100644 index 0000000000000..f4edcdaa9ca9f --- /dev/null +++ b/tests/ui/closures/binder/type-bound-2.rs @@ -0,0 +1,7 @@ +#![feature(closure_lifetime_binder, non_lifetime_binders)] +//~^ WARN is incomplete and may not be safe to use + +fn main() { + for || -> () {}; + //~^ ERROR late-bound type parameter not allowed on closures +} diff --git a/tests/ui/closures/binder/type-bound-2.stderr b/tests/ui/closures/binder/type-bound-2.stderr new file mode 100644 index 0000000000000..14b2dbf03957f --- /dev/null +++ b/tests/ui/closures/binder/type-bound-2.stderr @@ -0,0 +1,17 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/type-bound-2.rs:1:37 + | +LL | #![feature(closure_lifetime_binder, non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: late-bound type parameter not allowed on closures + --> $DIR/type-bound-2.rs:5:9 + | +LL | for || -> () {}; + | ^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/ui/closures/binder/type-bound.rs b/tests/ui/closures/binder/type-bound.rs new file mode 100644 index 0000000000000..59a3353f4965e --- /dev/null +++ b/tests/ui/closures/binder/type-bound.rs @@ -0,0 +1,7 @@ +#![feature(closure_lifetime_binder, non_lifetime_binders)] +//~^ WARN is incomplete and may not be safe to use + +fn main() { + for || -> T {}; + //~^ ERROR late-bound type parameter not allowed on closures +} diff --git a/tests/ui/closures/binder/type-bound.stderr b/tests/ui/closures/binder/type-bound.stderr new file mode 100644 index 0000000000000..ef00a2dffceae --- /dev/null +++ b/tests/ui/closures/binder/type-bound.stderr @@ -0,0 +1,17 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/type-bound.rs:1:37 + | +LL | #![feature(closure_lifetime_binder, non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: late-bound type parameter not allowed on closures + --> $DIR/type-bound.rs:5:9 + | +LL | for || -> T {}; + | ^ + +error: aborting due to previous error; 1 warning emitted +