1
Fork 0

Rollup merge of #134140 - compiler-errors:unsafe-binders-ast, r=oli-obk

Add AST support for unsafe binders

I'm splitting up #130514 into pieces. It's impossible for me to keep up with a huge PR like that. I'll land type system support for this next, probably w/o MIR lowering, which will come later.

r? `@oli-obk`
cc `@BoxyUwU` and `@lcnr` who also may want to look at this, though this PR doesn't do too much yet
This commit is contained in:
Matthias Krüger 2024-12-13 17:25:31 +01:00 committed by GitHub
commit 5c9b227a3d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 616 additions and 18 deletions

View file

@ -1382,6 +1382,7 @@ impl Expr {
| ExprKind::Tup(_) | ExprKind::Tup(_)
| ExprKind::Type(..) | ExprKind::Type(..)
| ExprKind::Underscore | ExprKind::Underscore
| ExprKind::UnsafeBinderCast(..)
| ExprKind::While(..) | ExprKind::While(..)
| ExprKind::Err(_) | ExprKind::Err(_)
| ExprKind::Dummy => ExprPrecedence::Unambiguous, | ExprKind::Dummy => ExprPrecedence::Unambiguous,
@ -1509,7 +1510,13 @@ pub enum ExprKind {
/// `'label: for await? pat in iter { block }` /// `'label: for await? pat in iter { block }`
/// ///
/// This is desugared to a combination of `loop` and `match` expressions. /// This is desugared to a combination of `loop` and `match` expressions.
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind }, ForLoop {
pat: P<Pat>,
iter: P<Expr>,
body: P<Block>,
label: Option<Label>,
kind: ForLoopKind,
},
/// Conditionless loop (can be exited with `break`, `continue`, or `return`). /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
/// ///
/// `'label: loop { block }` /// `'label: loop { block }`
@ -1614,6 +1621,8 @@ pub enum ExprKind {
/// A `format_args!()` expression. /// A `format_args!()` expression.
FormatArgs(P<FormatArgs>), FormatArgs(P<FormatArgs>),
UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
/// Placeholder for an expression that wasn't syntactically well formed in some way. /// Placeholder for an expression that wasn't syntactically well formed in some way.
Err(ErrorGuaranteed), Err(ErrorGuaranteed),
@ -1652,6 +1661,16 @@ impl GenBlockKind {
} }
} }
/// Whether we're unwrapping or wrapping an unsafe binder
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum UnsafeBinderCastKind {
// e.g. `&i32` -> `unsafe<'a> &'a i32`
Wrap,
// e.g. `unsafe<'a> &'a i32` -> `&i32`
Unwrap,
}
/// The explicit `Self` type in a "qualified path". The actual /// The explicit `Self` type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored /// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated /// separately. `position` represents the index of the associated
@ -2223,6 +2242,12 @@ pub struct BareFnTy {
pub decl_span: Span, pub decl_span: Span,
} }
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct UnsafeBinderTy {
pub generic_params: ThinVec<GenericParam>,
pub inner_ty: P<Ty>,
}
/// The various kinds of type recognized by the compiler. /// The various kinds of type recognized by the compiler.
// //
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`. // Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
@ -2242,6 +2267,8 @@ pub enum TyKind {
PinnedRef(Option<Lifetime>, MutTy), PinnedRef(Option<Lifetime>, MutTy),
/// A bare function (e.g., `fn(usize) -> bool`). /// A bare function (e.g., `fn(usize) -> bool`).
BareFn(P<BareFnTy>), BareFn(P<BareFnTy>),
/// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
UnsafeBinder(P<UnsafeBinderTy>),
/// The never type (`!`). /// The never type (`!`).
Never, Never,
/// A tuple (`(A, B, C, D,...)`). /// A tuple (`(A, B, C, D,...)`).

View file

@ -558,6 +558,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
vis.visit_fn_decl(decl); vis.visit_fn_decl(decl);
vis.visit_span(decl_span); 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::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Paren(ty) => vis.visit_ty(ty),
TyKind::Pat(ty, pat) => { TyKind::Pat(ty, pat) => {
@ -1780,6 +1785,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
ExprKind::TryBlock(body) => vis.visit_block(body), ExprKind::TryBlock(body) => vis.visit_block(body),
ExprKind::Lit(_token) => {} ExprKind::Lit(_token) => {}
ExprKind::IncludedBytes(_bytes) => {} ExprKind::IncludedBytes(_bytes) => {}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
vis.visit_expr(expr);
if let Some(ty) = ty {
vis.visit_ty(ty);
}
}
ExprKind::Err(_guar) => {} ExprKind::Err(_guar) => {}
ExprKind::Dummy => {} ExprKind::Dummy => {}
} }

View file

@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
| Underscore | Underscore
| Yeet(..) | Yeet(..)
| Yield(..) | Yield(..)
| UnsafeBinderCast(..)
| Err(..) | Err(..)
| Dummy => return false, | Dummy => return false,
} }
@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
| Paren(_) | Paren(_)
| Try(_) | Try(_)
| Yeet(None) | Yeet(None)
| UnsafeBinderCast(..)
| Err(_) | Err(_)
| Dummy => break None, | Dummy => break None,
} }
@ -253,6 +255,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
ty = &mut_ty.ty; ty = &mut_ty.ty;
} }
ast::TyKind::UnsafeBinder(binder) => {
ty = &binder.inner_ty;
}
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output { ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
ast::FnRetTy::Default(_) => break None, ast::FnRetTy::Default(_) => break None,
ast::FnRetTy::Ty(ret) => ty = ret, ast::FnRetTy::Ty(ret) => ty = ret,

View file

@ -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); walk_list!(visitor, visit_generic_param, generic_params);
try_visit!(visitor.visit_fn_decl(decl)); 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) => { TyKind::Path(maybe_qself, path) => {
try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_qself(maybe_qself));
try_visit!(visitor.visit_path(path, *id)); try_visit!(visitor.visit_path(path, *id));
@ -1226,6 +1230,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
ExprKind::Lit(_token) => {} ExprKind::Lit(_token) => {}
ExprKind::IncludedBytes(_bytes) => {} ExprKind::IncludedBytes(_bytes) => {}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty, ty);
}
ExprKind::Err(_guar) => {} ExprKind::Err(_guar) => {}
ExprKind::Dummy => {} ExprKind::Dummy => {}
} }

View file

@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err(guar) => hir::ExprKind::Err(*guar), ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
*kind,
self.lower_expr(expr),
ty.as_ref().map(|ty| {
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
}),
),
ExprKind::Dummy => { ExprKind::Dummy => {
span_bug!(e.span, "lowered ExprKind::Dummy") span_bug!(e.span, "lowered ExprKind::Dummy")
} }

View file

@ -1228,6 +1228,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_names: self.lower_fn_params_to_names(&f.decl), 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::Never => hir::TyKind::Never,
TyKind::Tup(tys) => hir::TyKind::Tup( TyKind::Tup(tys) => hir::TyKind::Tup(
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),

View file

@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(return_type_notation, "return type notation is experimental");
gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
gate_all!(unsafe_fields, "`unsafe` fields are experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental");
gate_all!(unsafe_binders, "unsafe binder types are experimental");
if !visitor.features.never_patterns() { if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) { if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -1198,6 +1198,14 @@ impl<'a> State<'a> {
ast::TyKind::BareFn(f) => { ast::TyKind::BareFn(f) => {
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params); 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) => { ast::TyKind::Path(None, path) => {
self.print_path(path, false, 0); self.print_path(path, false, 0);
} }

View file

@ -772,6 +772,25 @@ impl<'a> State<'a> {
self.word_nbsp("try"); self.word_nbsp("try");
self.print_block_with_attrs(blk, attrs) self.print_block_with_attrs(blk, attrs)
} }
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
self.word("builtin # ");
match kind {
ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"),
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"),
}
self.popen();
self.ibox(0);
self.print_expr(expr, FixupContext::default());
if let Some(ty) = ty {
self.word(",");
self.space();
self.print_type(ty);
}
self.end();
self.pclose();
}
ast::ExprKind::Err(_) => { ast::ExprKind::Err(_) => {
self.popen(); self.popen();
self.word("/*ERROR*/"); self.word("/*ERROR*/");

View file

@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::While(_, _, _) | ExprKind::While(_, _, _)
| ExprKind::Yeet(_) | ExprKind::Yeet(_)
| ExprKind::Become(_) | ExprKind::Become(_)
| ExprKind::Yield(_) => {} | ExprKind::Yield(_)
| ExprKind::UnsafeBinderCast(..) => {}
} }
} }

View file

@ -635,6 +635,8 @@ declare_features! (
/// Allows creation of instances of a struct by moving fields that have /// Allows creation of instances of a struct by moving fields that have
/// not changed from prior instances of the same struct (RFC #2528) /// not changed from prior instances of the same struct (RFC #2528)
(unstable, type_changing_struct_update, "1.58.0", Some(86555)), (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
/// Allows using `unsafe<'a> &'a T` unsafe binder types.
(incomplete, unsafe_binders, "CURRENT_RUSTC_VERSION", Some(130516)),
/// Allows declaring fields `unsafe`. /// Allows declaring fields `unsafe`.
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)), (incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
/// Allows const generic parameters to be defined with types that /// Allows const generic parameters to be defined with types that

View file

@ -8,7 +8,7 @@ use rustc_ast::{
}; };
pub use rustc_ast::{ pub use rustc_ast::{
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
ImplPolarity, IsAuto, Movability, Mutability, UnOp, ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
}; };
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::sorted_map::SortedMap;
@ -1740,6 +1740,7 @@ impl Expr<'_> {
| ExprKind::Struct(..) | ExprKind::Struct(..)
| ExprKind::Tup(_) | ExprKind::Tup(_)
| ExprKind::Type(..) | ExprKind::Type(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::Err(_) => ExprPrecedence::Unambiguous, | ExprKind::Err(_) => ExprPrecedence::Unambiguous,
ExprKind::DropTemps(ref expr, ..) => expr.precedence(), ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
@ -1769,6 +1770,9 @@ impl Expr<'_> {
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries // https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from), ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
// Unsafe binder cast preserves place-ness of the sub-expression.
ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
ExprKind::Unary(UnOp::Deref, _) => true, ExprKind::Unary(UnOp::Deref, _) => true,
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => { ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
@ -1850,7 +1854,8 @@ impl Expr<'_> {
| ExprKind::Field(base, _) | ExprKind::Field(base, _)
| ExprKind::Index(base, _, _) | ExprKind::Index(base, _, _)
| ExprKind::AddrOf(.., base) | ExprKind::AddrOf(.., base)
| ExprKind::Cast(base, _) => { | ExprKind::Cast(base, _)
| ExprKind::UnsafeBinderCast(_, base, _) => {
// This isn't exactly true for `Index` and all `Unary`, but we are using this // This isn't exactly true for `Index` and all `Unary`, but we are using this
// method exclusively for diagnostics and there's a *cultural* pressure against // method exclusively for diagnostics and there's a *cultural* pressure against
// them being used only for its side-effects. // them being used only for its side-effects.
@ -2144,6 +2149,10 @@ pub enum ExprKind<'hir> {
/// A suspension point for coroutines (i.e., `yield <expr>`). /// A suspension point for coroutines (i.e., `yield <expr>`).
Yield(&'hir Expr<'hir>, YieldSource), Yield(&'hir Expr<'hir>, YieldSource),
/// Operators which can be used to interconvert `unsafe` binder types.
/// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
/// A placeholder for an expression that wasn't syntactically well formed in some way. /// A placeholder for an expression that wasn't syntactically well formed in some way.
Err(rustc_span::ErrorGuaranteed), Err(rustc_span::ErrorGuaranteed),
} }
@ -2780,6 +2789,12 @@ pub struct BareFnTy<'hir> {
pub param_names: &'hir [Ident], 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)] #[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct OpaqueTy<'hir> { pub struct OpaqueTy<'hir> {
pub hir_id: HirId, pub hir_id: HirId,
@ -2878,6 +2893,8 @@ pub enum TyKind<'hir> {
Ref(&'hir Lifetime, MutTy<'hir>), Ref(&'hir Lifetime, MutTy<'hir>),
/// A bare function (e.g., `fn(usize) -> bool`). /// A bare function (e.g., `fn(usize) -> bool`).
BareFn(&'hir BareFnTy<'hir>), BareFn(&'hir BareFnTy<'hir>),
/// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`).
UnsafeBinder(&'hir UnsafeBinderTy<'hir>),
/// The never type (`!`). /// The never type (`!`).
Never, Never,
/// A tuple (`(A, B, C, D, ...)`). /// A tuple (`(A, B, C, D, ...)`).

View file

@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::Yield(ref subexpression, _) => { ExprKind::Yield(ref subexpression, _) => {
try_visit!(visitor.visit_expr(subexpression)); try_visit!(visitor.visit_expr(subexpression));
} }
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty, ty);
}
ExprKind::Lit(_) | ExprKind::Err(_) => {} ExprKind::Lit(_) | ExprKind::Err(_) => {}
} }
V::Result::output() V::Result::output()
@ -886,6 +890,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); walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
try_visit!(visitor.visit_fn_decl(function_declaration.decl)); 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) => { TyKind::Path(ref qpath) => {
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
} }

View file

@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
self.outer_index.shift_out(1); self.outer_index.shift_out(1);
res res
} }
hir::TyKind::UnsafeBinder(_) => {
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), _ => intravisit::walk_ty(self, ty),
} }
} }

View file

@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
intravisit::walk_ty(this, ty); intravisit::walk_ty(this, ty);
}); });
} }
hir::TyKind::UnsafeBinder(binder) => {
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, 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, _) => { hir::TyKind::TraitObject(bounds, lifetime, _) => {
debug!(?bounds, ?lifetime, "TraitObject"); debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope }; let scope = Scope::TraitRefBoundary { s: self.scope };

View file

@ -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)), 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) => { hir::TyKind::TraitObject(bounds, lifetime, repr) => {
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) { 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 // Don't continue with type analysis if the `dyn` keyword is missing

View file

@ -288,6 +288,9 @@ impl<'a> State<'a> {
hir::TyKind::BareFn(f) => { hir::TyKind::BareFn(f) => {
self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names); 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::OpaqueDef(..) => self.word("/*impl Trait*/"),
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false), hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
hir::TyKind::TraitObject(bounds, lifetime, syntax) => { hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
@ -339,6 +342,15 @@ impl<'a> State<'a> {
self.end() 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<'_>) { fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
self.hardbreak_if_not_bol(); self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo()); self.maybe_print_comment(item.span.lo());
@ -1530,6 +1542,19 @@ impl<'a> State<'a> {
self.word(")"); self.word(")");
} }
hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
match kind {
hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
}
self.print_expr(expr);
if let Some(ty) = ty {
self.word(",");
self.space();
self.print_type(ty);
}
self.word(")");
}
hir::ExprKind::Yield(expr, _) => { hir::ExprKind::Yield(expr, _) => {
self.word_space("yield"); self.word_space("yield");
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump); self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);

View file

@ -329,6 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Assignment does call `drop_in_place`, though, but its safety // Assignment does call `drop_in_place`, though, but its safety
// requirements are not the same. // requirements are not the same.
ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false, ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
// Place-preserving expressions only constitute reads if their
// parent expression constitutes a read.
ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => {
self.expr_guaranteed_to_constitute_read_for_never(expr)
}
ExprKind::Assign(lhs, _, _) => { ExprKind::Assign(lhs, _, _) => {
// Only the LHS does not constitute a read // Only the LHS does not constitute a read
expr.hir_id != lhs.hir_id expr.hir_id != lhs.hir_id
@ -353,7 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ExprKind::Binary(_, _, _) | ExprKind::Binary(_, _, _)
| ExprKind::Unary(_, _) | ExprKind::Unary(_, _)
| ExprKind::Cast(_, _) | ExprKind::Cast(_, _)
| ExprKind::Type(_, _)
| ExprKind::DropTemps(_) | ExprKind::DropTemps(_)
| ExprKind::If(_, _, _) | ExprKind::If(_, _, _)
| ExprKind::Closure(_) | ExprKind::Closure(_)
@ -564,7 +570,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_index(base, idx, expr, brackets_span) self.check_expr_index(base, idx, expr, brackets_span)
} }
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr), ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar), ExprKind::UnsafeBinderCast(kind, expr, ty) => {
self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
}
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
} }
} }
@ -1634,6 +1643,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
fn check_expr_unsafe_binder_cast(
&self,
_kind: hir::UnsafeBinderCastKind,
expr: &'tcx hir::Expr<'tcx>,
_hir_ty: Option<&'tcx hir::Ty<'tcx>>,
_expected: Expectation<'tcx>,
) -> Ty<'tcx> {
let guar =
self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
Ty::new_error(self.tcx, guar)
}
fn check_expr_array( fn check_expr_array(
&self, &self,
args: &'tcx [hir::Expr<'tcx>], args: &'tcx [hir::Expr<'tcx>],

View file

@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
self.walk_expr(subexpr)?; self.walk_expr(subexpr)?;
} }
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
self.walk_expr(subexpr)?;
}
hir::ExprKind::Unary(hir::UnOp::Deref, base) => { hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
// *base // *base
self.walk_expr(base)?; self.walk_expr(base)?;
@ -1360,7 +1364,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
self.cat_res(expr.hir_id, expr.span, expr_ty, res) self.cat_res(expr.hir_id, expr.span, expr_ty, res)
} }
// both type ascription and unsafe binder casts don't affect
// the place-ness of the subexpression.
hir::ExprKind::Type(e, _) => self.cat_expr(e), hir::ExprKind::Type(e, _) => self.cat_expr(e),
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
hir::ExprKind::AddrOf(..) hir::ExprKind::AddrOf(..)
| hir::ExprKind::Call(..) | hir::ExprKind::Call(..)

View file

@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
| ExprKind::DropTemps(..) | ExprKind::DropTemps(..)
| ExprKind::Let(..) => false, | ExprKind::Let(..) => false,
ExprKind::UnsafeBinderCast(..) => false,
// Not applicable // Not applicable
ExprKind::Type(..) | ExprKind::Err(..) => false, ExprKind::Type(..) | ExprKind::Err(..) => false,
} }

View file

@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
hir::ExprKind::Unary(_, expr) hir::ExprKind::Unary(_, expr)
| hir::ExprKind::Cast(expr, _) | hir::ExprKind::Cast(expr, _)
| hir::ExprKind::Type(expr, _) | hir::ExprKind::Type(expr, _)
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
| hir::ExprKind::Yield(expr, _) | hir::ExprKind::Yield(expr, _)
| hir::ExprKind::AddrOf(_, _, expr) | hir::ExprKind::AddrOf(_, _, expr)
| hir::ExprKind::Match(expr, _, _) | hir::ExprKind::Match(expr, _, _)

View file

@ -915,6 +915,11 @@ impl<'tcx> Cx<'tcx> {
} }
} }
} }
hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
unreachable!("unsafe binders are not yet implemented")
}
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) }, hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) }, hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },

View file

@ -15,7 +15,7 @@ use rustc_ast::visit::{Visitor, walk_expr};
use rustc_ast::{ use rustc_ast::{
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
}; };
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
@ -1931,6 +1931,12 @@ impl<'a> Parser<'a> {
Ok(match ident.name { Ok(match ident.name {
sym::offset_of => Some(this.parse_expr_offset_of(lo)?), sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?), sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
sym::wrap_binder => {
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
}
sym::unwrap_binder => {
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
}
_ => None, _ => None,
}) })
}) })
@ -2006,6 +2012,17 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::Type(expr, ty))) Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
} }
pub(crate) fn parse_expr_unsafe_binder_cast(
&mut self,
lo: Span,
kind: UnsafeBinderCastKind,
) -> PResult<'a, P<Expr>> {
let expr = self.parse_expr()?;
let ty = if self.eat(&TokenKind::Comma) { Some(self.parse_ty()?) } else { None };
let span = lo.to(self.token.span);
Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
}
/// Returns a string literal if the next token is a string literal. /// Returns a string literal if the next token is a string literal.
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
/// and returns `None` if the next token is not literal at all. /// and returns `None` if the next token is not literal at all.
@ -4016,7 +4033,9 @@ impl MutVisitor for CondChecker<'_> {
mut_visit::walk_expr(self, e); mut_visit::walk_expr(self, e);
self.forbid_let_reason = forbid_let_reason; self.forbid_let_reason = forbid_let_reason;
} }
ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => { ExprKind::Cast(ref mut op, _)
| ExprKind::Type(ref mut op, _)
| ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
let forbid_let_reason = self.forbid_let_reason; let forbid_let_reason = self.forbid_let_reason;
self.forbid_let_reason = Some(OtherForbidden); self.forbid_let_reason = Some(OtherForbidden);
self.visit_expr(op); self.visit_expr(op);

View file

@ -5,7 +5,7 @@ use rustc_ast::{
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
TyKind, TyKind, UnsafeBinderTy,
}; };
use rustc_errors::{Applicability, PResult}; use rustc_errors::{Applicability, PResult};
use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::symbol::{Ident, kw, sym};
@ -348,6 +348,10 @@ impl<'a> Parser<'a> {
TyKind::Err(guar) TyKind::Err(guar)
} }
} }
} else if self.check_keyword(kw::Unsafe)
&& self.look_ahead(1, |tok| matches!(tok.kind, token::Lt))
{
self.parse_unsafe_binder_ty()?
} else { } else {
let msg = format!("expected type, found {}", super::token_descr(&self.token)); let msg = format!("expected type, found {}", super::token_descr(&self.token));
let mut err = self.dcx().struct_span_err(lo, msg); let mut err = self.dcx().struct_span_err(lo, msg);
@ -369,6 +373,19 @@ impl<'a> Parser<'a> {
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } 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: /// Parses either:
/// - `(TYPE)`, a parenthesized type. /// - `(TYPE)`, a parenthesized type.
/// - `(TYPE,)`, a tuple with a single field of type TYPE. /// - `(TYPE,)`, a tuple with a single field of type TYPE.

View file

@ -315,9 +315,40 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn visit_expr(&mut self, e: &'v hir::Expr<'v>) { fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [ record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [
ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps, ConstBlock,
Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf, Array,
Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, Yield, Err Call,
MethodCall,
Tup,
Binary,
Unary,
Lit,
Cast,
Type,
DropTemps,
Let,
If,
Loop,
Match,
Closure,
Block,
Assign,
AssignOp,
Field,
Index,
Path,
AddrOf,
Break,
Continue,
Ret,
Become,
InlineAsm,
OffsetOf,
Struct,
Repeat,
Yield,
UnsafeBinderCast,
Err
]); ]);
hir_visit::walk_expr(self, e) hir_visit::walk_expr(self, e)
} }
@ -335,6 +366,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Ptr, Ptr,
Ref, Ref,
BareFn, BareFn,
UnsafeBinder,
Never, Never,
Tup, Tup,
Path, Path,
@ -571,7 +603,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
Become, IncludedBytes, Gen, Err, Dummy Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy
] ]
); );
ast_visit::walk_expr(self, e) ast_visit::walk_expr(self, e)
@ -585,6 +617,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Ref, Ref,
PinnedRef, PinnedRef,
BareFn, BareFn,
UnsafeBinder,
Never, Never,
Tup, Tup,
Path, Path,

View file

@ -447,6 +447,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
| hir::ExprKind::InlineAsm(..) | hir::ExprKind::InlineAsm(..)
| hir::ExprKind::OffsetOf(..) | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Type(..) | hir::ExprKind::Type(..)
| hir::ExprKind::UnsafeBinderCast(..)
| hir::ExprKind::Err(_) | hir::ExprKind::Err(_)
| hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => {} | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {}
@ -1051,6 +1052,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::AddrOf(_, _, ref e) hir::ExprKind::AddrOf(_, _, ref e)
| hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Cast(ref e, _)
| hir::ExprKind::Type(ref e, _) | hir::ExprKind::Type(ref e, _)
| hir::ExprKind::UnsafeBinderCast(_, ref e, _)
| hir::ExprKind::DropTemps(ref e) | hir::ExprKind::DropTemps(ref e)
| hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Unary(_, ref e)
| hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ), | hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ),
@ -1443,6 +1445,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
| hir::ExprKind::Path(_) | hir::ExprKind::Path(_)
| hir::ExprKind::Yield(..) | hir::ExprKind::Yield(..)
| hir::ExprKind::Type(..) | hir::ExprKind::Type(..)
| hir::ExprKind::UnsafeBinderCast(..)
| hir::ExprKind::Err(_) => {} | hir::ExprKind::Err(_) => {}
} }
} }

View file

@ -186,6 +186,7 @@ impl CheckInlineAssembly {
| ExprKind::Lit(..) | ExprKind::Lit(..)
| ExprKind::Cast(..) | ExprKind::Cast(..)
| ExprKind::Type(..) | ExprKind::Type(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::Loop(..) | ExprKind::Loop(..)
| ExprKind::Match(..) | ExprKind::Match(..)
| ExprKind::If(..) | ExprKind::If(..)

View file

@ -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) => { TyKind::Array(element_ty, length) => {
self.visit_ty(element_ty); self.visit_ty(element_ty);
self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No)); self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));

View file

@ -2105,6 +2105,7 @@ symbols! {
unreachable_macro, unreachable_macro,
unrestricted_attribute_tokens, unrestricted_attribute_tokens,
unsafe_attributes, unsafe_attributes,
unsafe_binders,
unsafe_block_in_unsafe_fn, unsafe_block_in_unsafe_fn,
unsafe_cell, unsafe_cell,
unsafe_cell_raw_get, unsafe_cell_raw_get,
@ -2128,6 +2129,7 @@ symbols! {
unwind_attributes, unwind_attributes,
unwind_safe_trait, unwind_safe_trait,
unwrap, unwrap,
unwrap_binder,
unwrap_or, unwrap_or,
use_extern_macros, use_extern_macros,
use_nested_groups, use_nested_groups,
@ -2186,6 +2188,7 @@ symbols! {
windows, windows,
windows_subsystem, windows_subsystem,
with_negative_coherence, with_negative_coherence,
wrap_binder,
wrapping_add, wrapping_add,
wrapping_div, wrapping_div,
wrapping_mul, wrapping_mul,

View file

@ -354,6 +354,8 @@ pub mod random;
pub mod range; pub mod range;
pub mod result; pub mod result;
pub mod sync; pub mod sync;
#[unstable(feature = "unsafe_binders", issue = "130516")]
pub mod unsafe_binder;
pub mod fmt; pub mod fmt;
pub mod hash; pub mod hash;

View file

@ -0,0 +1,25 @@
//! Operators used to turn types into unsafe binders and back.
/// Unwrap an unsafe binder into its underlying type.
#[allow_internal_unstable(builtin_syntax)]
#[unstable(feature = "unsafe_binders", issue = "130516")]
pub macro unwrap_binder {
($expr:expr) => {
builtin # unwrap_binder ( $expr )
},
($expr:expr ; $ty:ty) => {
builtin # unwrap_binder ( $expr, $ty )
},
}
/// Wrap a type into an unsafe binder.
#[allow_internal_unstable(builtin_syntax)]
#[unstable(feature = "unsafe_binders", issue = "130516")]
pub macro wrap_binder {
($expr:expr) => {
builtin # wrap_binder ( $expr )
},
($expr:expr ; $ty:ty) => {
builtin # wrap_binder ( $expr, $ty )
},
}

View file

@ -544,6 +544,8 @@ pub use core::u64;
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
#[allow(deprecated, deprecated_in_future)] #[allow(deprecated, deprecated_in_future)]
pub use core::u128; pub use core::u128;
#[unstable(feature = "unsafe_binders", issue = "130516")]
pub use core::unsafe_binder;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated, deprecated_in_future)] #[allow(deprecated, deprecated_in_future)]
pub use core::usize; pub use core::usize;

View file

@ -1841,6 +1841,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer, TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
TyKind::UnsafeBinder(..) => {
unimplemented!("unsafe binders are not supported yet")
}
} }
} }

View file

@ -819,6 +819,7 @@ impl TyCoercionStability {
| TyKind::TraitObject(..) | TyKind::TraitObject(..)
| TyKind::InferDelegation(..) | TyKind::InferDelegation(..)
| TyKind::Err(_) => Self::Reborrow, | TyKind::Err(_) => Self::Reborrow,
TyKind::UnsafeBinder(..) => Self::None,
}; };
} }
} }

View file

@ -156,7 +156,8 @@ fn never_loop_expr<'tcx>(
| ExprKind::Field(e, _) | ExprKind::Field(e, _)
| ExprKind::AddrOf(_, _, e) | ExprKind::AddrOf(_, _, e)
| ExprKind::Repeat(e, _) | ExprKind::Repeat(e, _)
| ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id), | ExprKind::DropTemps(e)
| ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id),
ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id), ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
ExprKind::MethodCall(_, receiver, es, _) => { ExprKind::MethodCall(_, receiver, es, _) => {

View file

@ -623,6 +623,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
kind!("DropTemps({expr})"); kind!("DropTemps({expr})");
self.expr(expr); self.expr(expr);
}, },
ExprKind::UnsafeBinderCast(..) => {
unimplemented!("unsafe binders are not implemented yet");
}
} }
} }

View file

@ -303,7 +303,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
| ExprKind::AddrOf(..) | ExprKind::AddrOf(..)
| ExprKind::Repeat(..) | ExprKind::Repeat(..)
| ExprKind::Block(Block { stmts: [], .. }, _) | ExprKind::Block(Block { stmts: [], .. }, _)
| ExprKind::OffsetOf(..) => (), | ExprKind::OffsetOf(..)
| ExprKind::UnsafeBinderCast(..) => (),
// Assignment might be to a local defined earlier, so don't eagerly evaluate. // Assignment might be to a local defined earlier, so don't eagerly evaluate.
// Blocks with multiple statements might be expensive, so don't eagerly evaluate. // Blocks with multiple statements might be expensive, so don't eagerly evaluate.

View file

@ -370,6 +370,10 @@ impl HirEqInterExpr<'_, '_, '_> {
&& self.eq_expr(l_receiver, r_receiver) && self.eq_expr(l_receiver, r_receiver)
&& self.eq_exprs(l_args, r_args) && self.eq_exprs(l_args, r_args)
}, },
(&ExprKind::UnsafeBinderCast(lkind, le, None), &ExprKind::UnsafeBinderCast(rkind, re, None)) =>
lkind == rkind && self.eq_expr(le, re),
(&ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), &ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) =>
lkind == rkind && self.eq_expr(le, re) && self.eq_ty(lt, rt),
(&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => { (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name) self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
}, },
@ -424,6 +428,7 @@ impl HirEqInterExpr<'_, '_, '_> {
| &ExprKind::Type(..) | &ExprKind::Type(..)
| &ExprKind::Unary(..) | &ExprKind::Unary(..)
| &ExprKind::Yield(..) | &ExprKind::Yield(..)
| &ExprKind::UnsafeBinderCast(..)
// --- Special cases that do not have a positive branch. // --- Special cases that do not have a positive branch.
@ -1032,6 +1037,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
std::mem::discriminant(&lop).hash(&mut self.s); std::mem::discriminant(&lop).hash(&mut self.s);
self.hash_expr(le); self.hash_expr(le);
}, },
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
std::mem::discriminant(&kind).hash(&mut self.s);
self.hash_expr(expr);
if let Some(ty) = ty {
self.hash_ty(ty);
}
}
ExprKind::Err(_) => {}, ExprKind::Err(_) => {},
} }
} }
@ -1241,6 +1253,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
TyKind::Typeof(anon_const) => { TyKind::Typeof(anon_const) => {
self.hash_body(anon_const.body); self.hash_body(anon_const.body);
}, },
TyKind::UnsafeBinder(binder) => {
self.hash_ty(binder.inner_ty);
}
TyKind::Err(_) TyKind::Err(_)
| TyKind::Infer | TyKind::Infer
| TyKind::Never | TyKind::Never

View file

@ -151,7 +151,8 @@ impl<'a> Sugg<'a> {
| ExprKind::Become(..) | ExprKind::Become(..)
| ExprKind::Struct(..) | ExprKind::Struct(..)
| ExprKind::Tup(..) | ExprKind::Tup(..)
| ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)), | ExprKind::Err(_)
| ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)),
ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
ExprKind::Assign(lhs, rhs, _) => { ExprKind::Assign(lhs, rhs, _) => {
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
@ -226,7 +227,8 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::While(..) | ast::ExprKind::While(..)
| ast::ExprKind::Await(..) | ast::ExprKind::Await(..)
| ast::ExprKind::Err(_) | ast::ExprKind::Err(_)
| ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)), | ast::ExprKind::Dummy
| ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)),
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
AssocOp::DotDot, AssocOp::DotDot,
lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),

View file

@ -694,6 +694,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
| ExprKind::Continue(_) | ExprKind::Continue(_)
| ExprKind::InlineAsm(_) | ExprKind::InlineAsm(_)
| ExprKind::OffsetOf(..) | ExprKind::OffsetOf(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::Err(_) => (), | ExprKind::Err(_) => (),
} }
ControlFlow::Continue(()) ControlFlow::Continue(())

View file

@ -413,7 +413,8 @@ pub(crate) fn format_expr(
ast::ExprKind::FormatArgs(..) ast::ExprKind::FormatArgs(..)
| ast::ExprKind::Type(..) | ast::ExprKind::Type(..)
| ast::ExprKind::IncludedBytes(..) | ast::ExprKind::IncludedBytes(..)
| ast::ExprKind::OffsetOf(..) => { | ast::ExprKind::OffsetOf(..)
| ast::ExprKind::UnsafeBinderCast(..) => {
// These don't normally occur in the AST because macros aren't expanded. However, // These don't normally occur in the AST because macros aren't expanded. However,
// rustfmt tries to parse macro arguments when formatting macros, so it's not totally // rustfmt tries to parse macro arguments when formatting macros, so it's not totally
// impossible for rustfmt to come across one of these nodes when formatting a file. // impossible for rustfmt to come across one of these nodes when formatting a file.

View file

@ -1016,6 +1016,31 @@ impl Rewrite for ast::Ty {
let pat = pat.rewrite_result(context, shape)?; let pat = pat.rewrite_result(context, shape)?;
Ok(format!("{ty} is {pat}")) Ok(format!("{ty} is {pat}"))
} }
ast::TyKind::UnsafeBinder(ref binder) => {
let mut result = String::new();
if let Some(ref lifetime_str) =
rewrite_bound_params(context, shape, &binder.generic_params)
{
result.push_str("unsafe<");
result.push_str(lifetime_str);
result.push_str("> ");
}
let inner_ty_shape = if context.use_block_indent() {
shape
.offset_left(result.len())
.max_width_error(shape.width, self.span())?
} else {
shape
.visual_indent(result.len())
.sub_width(result.len())
.max_width_error(shape.width, self.span())?
};
let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?;
result.push_str(&rewrite);
Ok(result)
}
} }
} }
} }

View file

@ -504,6 +504,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
| ast::ExprKind::IncludedBytes(..) | ast::ExprKind::IncludedBytes(..)
| ast::ExprKind::InlineAsm(..) | ast::ExprKind::InlineAsm(..)
| ast::ExprKind::OffsetOf(..) | ast::ExprKind::OffsetOf(..)
| ast::ExprKind::UnsafeBinderCast(..)
| ast::ExprKind::Let(..) | ast::ExprKind::Let(..)
| ast::ExprKind::Path(..) | ast::ExprKind::Path(..)
| ast::ExprKind::Range(..) | ast::ExprKind::Range(..)

View file

@ -0,0 +1,11 @@
fn foo() -> unsafe<'a>
&'a () {}
struct Foo {
x: unsafe<'a>
&'a (),
}
struct Bar(unsafe<'a> &'a ());
impl Trait for unsafe<'a> &'a () {}

View file

@ -0,0 +1,9 @@
fn foo() -> unsafe<'a> &'a () {}
struct Foo {
x: unsafe<'a> &'a (),
}
struct Bar(unsafe<'a> &'a ());
impl Trait for unsafe<'a> &'a () {}

View file

@ -0,0 +1,7 @@
#[cfg(any())]
fn test() {
let x: unsafe<> ();
//~^ ERROR unsafe binder types are experimental
}
fn main() {}

View file

@ -0,0 +1,13 @@
error[E0658]: unsafe binder types are experimental
--> $DIR/feature-gate-unsafe-binders.rs:3:12
|
LL | let x: unsafe<> ();
| ^^^^^^^^^^^
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= help: add `#![feature(unsafe_binders)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,13 @@
#![feature(unsafe_binders)]
//~^ WARN the feature `unsafe_binders` is incomplete
use std::unsafe_binder::{wrap_binder, unwrap_binder};
fn main() {
let x = 1;
let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
//~^ ERROR unsafe binders are not yet implemented
//~| ERROR unsafe binders are not yet implemented
let rx = *unwrap_binder!(binder);
//~^ ERROR unsafe binders are not yet implemented
}

View file

@ -0,0 +1,29 @@
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/expr.rs:1:12
|
LL | #![feature(unsafe_binders)]
| ^^^^^^^^^^^^^^
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= note: `#[warn(incomplete_features)]` on by default
error: unsafe binders are not yet implemented
--> $DIR/expr.rs:8:17
|
LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
| ^^^^^^^^^^^^^^^^^^
error: unsafe binders are not yet implemented
--> $DIR/expr.rs:8:51
|
LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(x);
| ^
error: unsafe binders are not yet implemented
--> $DIR/expr.rs:11:30
|
LL | let rx = *unwrap_binder!(binder);
| ^^^^^^
error: aborting due to 3 previous errors; 1 warning emitted

View file

@ -0,0 +1,19 @@
#![feature(unsafe_binders)]
//~^ WARN the feature `unsafe_binders` is incomplete
fn foo<'a>() {
let good: unsafe<'b> &'a &'b ();
//~^ ERROR unsafe binders are not yet implemented
let missing: unsafe<> &'missing ();
//~^ ERROR unsafe binders are not yet implemented
//~| ERROR use of undeclared lifetime name `'missing`
fn inner<'b>() {
let outer: unsafe<> &'a &'b ();
//~^ ERROR unsafe binders are not yet implemented
//~| can't use generic parameters from outer item
}
}
fn main() {}

View file

@ -0,0 +1,65 @@
error[E0261]: use of undeclared lifetime name `'missing`
--> $DIR/lifetime-resolution.rs:8:28
|
LL | let missing: unsafe<> &'missing ();
| ^^^^^^^^ undeclared lifetime
|
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider making the type lifetime-generic with a new `'missing` lifetime
|
LL | let missing: unsafe<'missing, > &'missing ();
| +++++++++
help: consider introducing lifetime `'missing` here
|
LL | fn foo<'missing, 'a>() {
| +++++++++
error[E0401]: can't use generic parameters from outer item
--> $DIR/lifetime-resolution.rs:13:30
|
LL | fn foo<'a>() {
| -- lifetime parameter from outer item
...
LL | let outer: unsafe<> &'a &'b ();
| ^^ use of generic parameter from outer item
|
help: consider making the type lifetime-generic with a new `'a` lifetime
|
LL | let outer: unsafe<'a, > &'a &'b ();
| +++
help: consider introducing lifetime `'a` here
|
LL | fn inner<'a, 'b>() {
| +++
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/lifetime-resolution.rs:1:12
|
LL | #![feature(unsafe_binders)]
| ^^^^^^^^^^^^^^
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= note: `#[warn(incomplete_features)]` on by default
error: unsafe binders are not yet implemented
--> $DIR/lifetime-resolution.rs:5:15
|
LL | let good: unsafe<'b> &'a &'b ();
| ^^^^^^^^^^^^^^^^^^^^^
error: unsafe binders are not yet implemented
--> $DIR/lifetime-resolution.rs:8:18
|
LL | let missing: unsafe<> &'missing ();
| ^^^^^^^^^^^^^^^^^^^^^
error: unsafe binders are not yet implemented
--> $DIR/lifetime-resolution.rs:13:20
|
LL | let outer: unsafe<> &'a &'b ();
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors; 1 warning emitted
Some errors have detailed explanations: E0261, E0401.
For more information about an error, try `rustc --explain E0261`.

View file

@ -0,0 +1,7 @@
#![feature(unsafe_binders)]
//~^ WARN the feature `unsafe_binders` is incomplete
fn main() {
let x: unsafe<'a> &'a ();
//~^ ERROR unsafe binders are not yet implemented
}

View file

@ -0,0 +1,17 @@
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/simple.rs:1:12
|
LL | #![feature(unsafe_binders)]
| ^^^^^^^^^^^^^^
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= note: `#[warn(incomplete_features)]` on by default
error: unsafe binders are not yet implemented
--> $DIR/simple.rs:5:12
|
LL | let x: unsafe<'a> &'a ();
| ^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error; 1 warning emitted