1
Fork 0

Add unwrap_unsafe_binder and wrap_unsafe_binder macro operators

This commit is contained in:
Michael Goulet 2024-09-13 14:00:10 -04:00
parent 2a9e358c72
commit 3f97c6be8d
25 changed files with 222 additions and 12 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

View file

@ -1780,6 +1780,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,
} }

View file

@ -1230,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

@ -565,6 +565,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

@ -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),
} }

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()

View file

@ -1542,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.
@ -4019,7 +4036,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

@ -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)
} }
@ -572,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)

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

@ -2104,6 +2104,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,
@ -2127,6 +2128,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,
@ -2185,6 +2187,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;