From 3b1adfa94b5851894b7b59a39ffe4c3e2a3c583a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 30 Aug 2024 17:01:28 -0400 Subject: [PATCH 1/5] Parsing unsafe binders --- compiler/rustc_ast/src/ast.rs | 8 ++++++++ compiler/rustc_ast/src/mut_visit.rs | 5 +++++ compiler/rustc_ast/src/util/classify.rs | 4 ++++ compiler/rustc_ast/src/visit.rs | 4 ++++ compiler/rustc_ast_pretty/src/pprust/state.rs | 8 ++++++++ compiler/rustc_parse/src/parser/ty.rs | 17 ++++++++++++++++- 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 650525a2f520e..5ffad332bcd83 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2223,6 +2223,12 @@ pub struct BareFnTy { pub decl_span: Span, } +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct UnsafeBinderTy { + pub generic_params: ThinVec, + pub inner_ty: P, +} + /// The various kinds of type recognized by the compiler. // // Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`. @@ -2242,6 +2248,8 @@ pub enum TyKind { PinnedRef(Option, MutTy), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(P), + /// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`). + UnsafeBinder(P), /// The never type (`!`). Never, /// A tuple (`(A, B, C, D,...)`). diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2c09059fe1904..4105926002d6c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -558,6 +558,11 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { vis.visit_fn_decl(decl); vis.visit_span(decl_span); } + TyKind::UnsafeBinder(binder) => { + let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut(); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); + vis.visit_ty(inner_ty); + } TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Pat(ty, pat) => { diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index ae1ca36a3ba93..41ab0f695f100 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -253,6 +253,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { ty = &mut_ty.ty; } + ast::TyKind::UnsafeBinder(binder) => { + ty = &binder.inner_ty; + } + ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output { ast::FnRetTy::Default(_) => break None, ast::FnRetTy::Ty(ret) => ty = ret, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a7f7c37693a84..6b36262bc1f74 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -522,6 +522,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { walk_list!(visitor, visit_generic_param, generic_params); try_visit!(visitor.visit_fn_decl(decl)); } + TyKind::UnsafeBinder(binder) => { + walk_list!(visitor, visit_generic_param, &binder.generic_params); + try_visit!(visitor.visit_ty(&binder.inner_ty)); + } TyKind::Path(maybe_qself, path) => { try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 49e4a559e7382..04ffa2cffe3e3 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1198,6 +1198,14 @@ impl<'a> State<'a> { ast::TyKind::BareFn(f) => { self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params); } + ast::TyKind::UnsafeBinder(f) => { + self.ibox(INDENT_UNIT); + self.word("unsafe"); + self.print_generic_params(&f.generic_params); + self.nbsp(); + self.print_type(&f.inner_ty); + self.end(); + } ast::TyKind::Path(None, path) => { self.print_path(path, false, 0); } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8cff23c2e32cb..92ce57bbc9295 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -5,7 +5,7 @@ use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, - TyKind, + TyKind, UnsafeBinderTy, }; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{Ident, kw, sym}; @@ -348,6 +348,8 @@ impl<'a> Parser<'a> { TyKind::Err(guar) } } + } else if self.check_keyword(kw::Unsafe) { + self.parse_unsafe_binder_ty()? } else { let msg = format!("expected type, found {}", super::token_descr(&self.token)); let mut err = self.dcx().struct_span_err(lo, msg); @@ -369,6 +371,19 @@ impl<'a> Parser<'a> { if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } + fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> { + let lo = self.token.span; + assert!(self.eat_keyword(kw::Unsafe)); + self.expect_lt()?; + let generic_params = self.parse_generic_params()?; + self.expect_gt()?; + let inner_ty = self.parse_ty()?; + let span = lo.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::unsafe_binders, span); + + Ok(TyKind::UnsafeBinder(P(UnsafeBinderTy { generic_params, inner_ty }))) + } + /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. From 2a9e358c723b03cc6adbce9c2c5af36cb2d83914 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 10 Dec 2024 20:10:56 +0000 Subject: [PATCH 2/5] Lower AST and resolve lifetimes for unsafe binder types --- compiler/rustc_ast_lowering/src/lib.rs | 7 +++++ compiler/rustc_hir/src/hir.rs | 8 +++++ compiler/rustc_hir/src/intravisit.rs | 4 +++ .../src/collect/generics_of.rs | 6 ++++ .../src/collect/resolve_bound_vars.rs | 30 +++++++++++++++++++ .../src/hir_ty_lowering/mod.rs | 7 +++++ compiler/rustc_hir_pretty/src/lib.rs | 12 ++++++++ compiler/rustc_passes/src/input_stats.rs | 2 ++ compiler/rustc_resolve/src/late.rs | 22 ++++++++++++++ 9 files changed, 98 insertions(+) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bac3f974ccae9..3cbd3e1b63785 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1228,6 +1228,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_names: self.lower_fn_params_to_names(&f.decl), })) } + TyKind::UnsafeBinder(f) => { + let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); + hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy { + generic_params, + inner_ty: self.lower_ty(&f.inner_ty, itctx), + })) + } TyKind::Never => hir::TyKind::Never, TyKind::Tup(tys) => hir::TyKind::Tup( self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4800a479ff460..bd8e660f9f1d7 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2780,6 +2780,12 @@ pub struct BareFnTy<'hir> { pub param_names: &'hir [Ident], } +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct UnsafeBinderTy<'hir> { + pub generic_params: &'hir [GenericParam<'hir>], + pub inner_ty: &'hir Ty<'hir>, +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct OpaqueTy<'hir> { pub hir_id: HirId, @@ -2878,6 +2884,8 @@ pub enum TyKind<'hir> { Ref(&'hir Lifetime, MutTy<'hir>), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(&'hir BareFnTy<'hir>), + /// Uwu + UnsafeBinder(&'hir UnsafeBinderTy<'hir>), /// The never type (`!`). Never, /// A tuple (`(A, B, C, D, ...)`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8dbfefffee4eb..2a49fcde2c09a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -886,6 +886,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul walk_list!(visitor, visit_generic_param, function_declaration.generic_params); try_visit!(visitor.visit_fn_decl(function_declaration.decl)); } + TyKind::UnsafeBinder(ref unsafe_binder) => { + walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params); + try_visit!(visitor.visit_ty(unsafe_binder.inner_ty)); + } TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 1d9114b0ef34e..f52d4f42eca4b 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option { + self.outer_index.shift_in(1); + let res = intravisit::walk_ty(self, ty); + self.outer_index.shift_out(1); + res + } _ => intravisit::walk_ty(self, ty), } } 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 74f381d266116..923d2b1fe6758 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { intravisit::walk_ty(this, ty); }); } + hir::TyKind::UnsafeBinder(binder) => { + let (mut bound_vars, binders): (FxIndexMap, Vec<_>) = + binder + .generic_params + .iter() + .enumerate() + .map(|(late_bound_idx, param)| { + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) + }) + .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, + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: None, + }; + self.with(scope, |this| { + // a bare fn has no bounds, so everything + // contained within is scoped within its binder. + intravisit::walk_ty(this, ty); + }); + } hir::TyKind::TraitObject(bounds, lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); let scope = Scope::TraitRefBoundary { s: self.scope }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7683c87168bae..1bdbde3003717 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2312,6 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)), ) } + hir::TyKind::UnsafeBinder(_binder) => { + let guar = self + .dcx() + .struct_span_err(hir_ty.span, "unsafe binders are not yet implemented") + .emit(); + Ty::new_error(tcx, guar) + } hir::TyKind::TraitObject(bounds, lifetime, repr) => { if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) { // Don't continue with type analysis if the `dyn` keyword is missing diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 20ba9ae2632ab..5782e3e7d3cd2 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -288,6 +288,9 @@ impl<'a> State<'a> { hir::TyKind::BareFn(f) => { self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names); } + hir::TyKind::UnsafeBinder(unsafe_binder) => { + self.print_unsafe_binder(unsafe_binder); + } hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"), hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false), hir::TyKind::TraitObject(bounds, lifetime, syntax) => { @@ -339,6 +342,15 @@ impl<'a> State<'a> { self.end() } + fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) { + self.ibox(INDENT_UNIT); + self.word("unsafe"); + self.print_generic_params(unsafe_binder.generic_params); + self.nbsp(); + self.print_type(unsafe_binder.inner_ty); + self.end(); + } + fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 76edb51c0bc0c..d5e6ca491aef8 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -335,6 +335,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Ptr, Ref, BareFn, + UnsafeBinder, Never, Tup, Path, @@ -585,6 +586,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Ref, PinnedRef, BareFn, + UnsafeBinder, Never, Tup, Path, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 789d74876f722..c80b02b6a7e5a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -887,6 +887,28 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }, ) } + TyKind::UnsafeBinder(unsafe_binder) => { + // FIXME(unsafe_binder): Better span + let span = ty.span; + self.with_generic_param_rib( + &unsafe_binder.generic_params, + RibKind::Normal, + LifetimeRibKind::Generics { + binder: ty.id, + kind: LifetimeBinderKind::BareFnType, + span, + }, + |this| { + this.visit_generic_params(&unsafe_binder.generic_params, false); + this.with_lifetime_rib( + // We don't allow anonymous `unsafe &'_ ()` binders, + // although I guess we could. + LifetimeRibKind::AnonymousReportError, + |this| this.visit_ty(&unsafe_binder.inner_ty), + ); + }, + ) + } TyKind::Array(element_ty, length) => { self.visit_ty(element_ty); self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No)); From 3f97c6be8d4b78c9df55804171c588ebfadcb63e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 13 Sep 2024 14:00:10 -0400 Subject: [PATCH 3/5] Add unwrap_unsafe_binder and wrap_unsafe_binder macro operators --- compiler/rustc_ast/src/ast.rs | 21 +++++++++- compiler/rustc_ast/src/mut_visit.rs | 6 +++ compiler/rustc_ast/src/util/classify.rs | 2 + compiler/rustc_ast/src/visit.rs | 4 ++ compiler/rustc_ast_lowering/src/expr.rs | 8 ++++ compiler/rustc_ast_passes/src/feature_gate.rs | 1 + .../rustc_ast_pretty/src/pprust/state/expr.rs | 19 +++++++++ .../src/assert/context.rs | 3 +- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir/src/hir.rs | 13 ++++++- compiler/rustc_hir/src/intravisit.rs | 4 ++ compiler/rustc_hir_pretty/src/lib.rs | 13 +++++++ compiler/rustc_hir_typeck/src/expr.rs | 25 +++++++++++- .../rustc_hir_typeck/src/expr_use_visitor.rs | 7 ++++ compiler/rustc_lint/src/dangling.rs | 2 + compiler/rustc_lint/src/if_let_rescope.rs | 1 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 5 +++ compiler/rustc_parse/src/parser/expr.rs | 23 ++++++++++- compiler/rustc_passes/src/input_stats.rs | 39 +++++++++++++++++-- compiler/rustc_passes/src/liveness.rs | 3 ++ compiler/rustc_passes/src/naked_functions.rs | 1 + compiler/rustc_span/src/symbol.rs | 3 ++ library/core/src/lib.rs | 2 + library/core/src/unsafe_binder.rs | 25 ++++++++++++ library/std/src/lib.rs | 2 + 25 files changed, 222 insertions(+), 12 deletions(-) create mode 100644 library/core/src/unsafe_binder.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5ffad332bcd83..697ee275a9b33 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1382,6 +1382,7 @@ impl Expr { | ExprKind::Tup(_) | ExprKind::Type(..) | ExprKind::Underscore + | ExprKind::UnsafeBinderCast(..) | ExprKind::While(..) | ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Unambiguous, @@ -1509,7 +1510,13 @@ pub enum ExprKind { /// `'label: for await? pat in iter { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - ForLoop { pat: P, iter: P, body: P, label: Option