Skip to content

Commit 3f97c6b

Browse files
Add unwrap_unsafe_binder and wrap_unsafe_binder macro operators
1 parent 2a9e358 commit 3f97c6b

File tree

25 files changed

+222
-12
lines changed

25 files changed

+222
-12
lines changed

Diff for: compiler/rustc_ast/src/ast.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,7 @@ impl Expr {
13821382
| ExprKind::Tup(_)
13831383
| ExprKind::Type(..)
13841384
| ExprKind::Underscore
1385+
| ExprKind::UnsafeBinderCast(..)
13851386
| ExprKind::While(..)
13861387
| ExprKind::Err(_)
13871388
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
@@ -1509,7 +1510,13 @@ pub enum ExprKind {
15091510
/// `'label: for await? pat in iter { block }`
15101511
///
15111512
/// This is desugared to a combination of `loop` and `match` expressions.
1512-
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
1513+
ForLoop {
1514+
pat: P<Pat>,
1515+
iter: P<Expr>,
1516+
body: P<Block>,
1517+
label: Option<Label>,
1518+
kind: ForLoopKind,
1519+
},
15131520
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
15141521
///
15151522
/// `'label: loop { block }`
@@ -1614,6 +1621,8 @@ pub enum ExprKind {
16141621
/// A `format_args!()` expression.
16151622
FormatArgs(P<FormatArgs>),
16161623

1624+
UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
1625+
16171626
/// Placeholder for an expression that wasn't syntactically well formed in some way.
16181627
Err(ErrorGuaranteed),
16191628

@@ -1652,6 +1661,16 @@ impl GenBlockKind {
16521661
}
16531662
}
16541663

1664+
/// Whether we're unwrapping or wrapping an unsafe binder
1665+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1666+
#[derive(Encodable, Decodable, HashStable_Generic)]
1667+
pub enum UnsafeBinderCastKind {
1668+
// e.g. `&i32` -> `unsafe<'a> &'a i32`
1669+
Wrap,
1670+
// e.g. `unsafe<'a> &'a i32` -> `&i32`
1671+
Unwrap,
1672+
}
1673+
16551674
/// The explicit `Self` type in a "qualified path". The actual
16561675
/// path, including the trait and the associated item, is stored
16571676
/// separately. `position` represents the index of the associated

Diff for: compiler/rustc_ast/src/mut_visit.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
17801780
ExprKind::TryBlock(body) => vis.visit_block(body),
17811781
ExprKind::Lit(_token) => {}
17821782
ExprKind::IncludedBytes(_bytes) => {}
1783+
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
1784+
vis.visit_expr(expr);
1785+
if let Some(ty) = ty {
1786+
vis.visit_ty(ty);
1787+
}
1788+
}
17831789
ExprKind::Err(_guar) => {}
17841790
ExprKind::Dummy => {}
17851791
}

Diff for: compiler/rustc_ast/src/util/classify.rs

+2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
152152
| Underscore
153153
| Yeet(..)
154154
| Yield(..)
155+
| UnsafeBinderCast(..)
155156
| Err(..)
156157
| Dummy => return false,
157158
}
@@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
232233
| Paren(_)
233234
| Try(_)
234235
| Yeet(None)
236+
| UnsafeBinderCast(..)
235237
| Err(_)
236238
| Dummy => break None,
237239
}

Diff for: compiler/rustc_ast/src/visit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
12301230
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
12311231
ExprKind::Lit(_token) => {}
12321232
ExprKind::IncludedBytes(_bytes) => {}
1233+
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
1234+
try_visit!(visitor.visit_expr(expr));
1235+
visit_opt!(visitor, visit_ty, ty);
1236+
}
12331237
ExprKind::Err(_guar) => {}
12341238
ExprKind::Dummy => {}
12351239
}

Diff for: compiler/rustc_ast_lowering/src/expr.rs

+8
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
379379
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
380380
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
381381

382+
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
383+
*kind,
384+
self.lower_expr(expr),
385+
ty.as_ref().map(|ty| {
386+
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
387+
}),
388+
),
389+
382390
ExprKind::Dummy => {
383391
span_bug!(e.span, "lowered ExprKind::Dummy")
384392
}

Diff for: compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
565565
gate_all!(return_type_notation, "return type notation is experimental");
566566
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
567567
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
568+
gate_all!(unsafe_binders, "unsafe binder types are experimental");
568569

569570
if !visitor.features.never_patterns() {
570571
if let Some(spans) = spans.get(&sym::never_patterns) {

Diff for: compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+19
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,25 @@ impl<'a> State<'a> {
772772
self.word_nbsp("try");
773773
self.print_block_with_attrs(blk, attrs)
774774
}
775+
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
776+
self.word("builtin # ");
777+
match kind {
778+
ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"),
779+
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"),
780+
}
781+
self.popen();
782+
self.ibox(0);
783+
self.print_expr(expr, FixupContext::default());
784+
785+
if let Some(ty) = ty {
786+
self.word(",");
787+
self.space();
788+
self.print_type(ty);
789+
}
790+
791+
self.end();
792+
self.pclose();
793+
}
775794
ast::ExprKind::Err(_) => {
776795
self.popen();
777796
self.word("/*ERROR*/");

Diff for: compiler/rustc_builtin_macros/src/assert/context.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
323323
| ExprKind::While(_, _, _)
324324
| ExprKind::Yeet(_)
325325
| ExprKind::Become(_)
326-
| ExprKind::Yield(_) => {}
326+
| ExprKind::Yield(_)
327+
| ExprKind::UnsafeBinderCast(..) => {}
327328
}
328329
}
329330

Diff for: compiler/rustc_feature/src/unstable.rs

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

Diff for: compiler/rustc_hir/src/hir.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_ast::{
88
};
99
pub use rustc_ast::{
1010
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
11-
ImplPolarity, IsAuto, Movability, Mutability, UnOp,
11+
ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
1212
};
1313
use rustc_data_structures::fingerprint::Fingerprint;
1414
use rustc_data_structures::sorted_map::SortedMap;
@@ -1740,6 +1740,7 @@ impl Expr<'_> {
17401740
| ExprKind::Struct(..)
17411741
| ExprKind::Tup(_)
17421742
| ExprKind::Type(..)
1743+
| ExprKind::UnsafeBinderCast(..)
17431744
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
17441745

17451746
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
@@ -1769,6 +1770,9 @@ impl Expr<'_> {
17691770
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
17701771
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
17711772

1773+
// Unsafe binder cast preserves place-ness of the sub-expression.
1774+
ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
1775+
17721776
ExprKind::Unary(UnOp::Deref, _) => true,
17731777

17741778
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
@@ -1850,7 +1854,8 @@ impl Expr<'_> {
18501854
| ExprKind::Field(base, _)
18511855
| ExprKind::Index(base, _, _)
18521856
| ExprKind::AddrOf(.., base)
1853-
| ExprKind::Cast(base, _) => {
1857+
| ExprKind::Cast(base, _)
1858+
| ExprKind::UnsafeBinderCast(_, base, _) => {
18541859
// This isn't exactly true for `Index` and all `Unary`, but we are using this
18551860
// method exclusively for diagnostics and there's a *cultural* pressure against
18561861
// them being used only for its side-effects.
@@ -2144,6 +2149,10 @@ pub enum ExprKind<'hir> {
21442149
/// A suspension point for coroutines (i.e., `yield <expr>`).
21452150
Yield(&'hir Expr<'hir>, YieldSource),
21462151

2152+
/// Operators which can be used to interconvert `unsafe` binder types.
2153+
/// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
2154+
UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
2155+
21472156
/// A placeholder for an expression that wasn't syntactically well formed in some way.
21482157
Err(rustc_span::ErrorGuaranteed),
21492158
}

Diff for: compiler/rustc_hir/src/intravisit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
857857
ExprKind::Yield(ref subexpression, _) => {
858858
try_visit!(visitor.visit_expr(subexpression));
859859
}
860+
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
861+
try_visit!(visitor.visit_expr(expr));
862+
visit_opt!(visitor, visit_ty, ty);
863+
}
860864
ExprKind::Lit(_) | ExprKind::Err(_) => {}
861865
}
862866
V::Result::output()

Diff for: compiler/rustc_hir_pretty/src/lib.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,19 @@ impl<'a> State<'a> {
15421542

15431543
self.word(")");
15441544
}
1545+
hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
1546+
match kind {
1547+
hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
1548+
hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
1549+
}
1550+
self.print_expr(expr);
1551+
if let Some(ty) = ty {
1552+
self.word(",");
1553+
self.space();
1554+
self.print_type(ty);
1555+
}
1556+
self.word(")");
1557+
}
15451558
hir::ExprKind::Yield(expr, _) => {
15461559
self.word_space("yield");
15471560
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);

Diff for: compiler/rustc_hir_typeck/src/expr.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
329329
// Assignment does call `drop_in_place`, though, but its safety
330330
// requirements are not the same.
331331
ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
332+
333+
// Place-preserving expressions only constitute reads if their
334+
// parent expression constitutes a read.
335+
ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => {
336+
self.expr_guaranteed_to_constitute_read_for_never(expr)
337+
}
338+
332339
ExprKind::Assign(lhs, _, _) => {
333340
// Only the LHS does not constitute a read
334341
expr.hir_id != lhs.hir_id
@@ -353,7 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
353360
| ExprKind::Binary(_, _, _)
354361
| ExprKind::Unary(_, _)
355362
| ExprKind::Cast(_, _)
356-
| ExprKind::Type(_, _)
357363
| ExprKind::DropTemps(_)
358364
| ExprKind::If(_, _, _)
359365
| ExprKind::Closure(_)
@@ -564,7 +570,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
564570
self.check_expr_index(base, idx, expr, brackets_span)
565571
}
566572
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
567-
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
573+
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
574+
self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
575+
}
576+
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
568577
}
569578
}
570579

@@ -1634,6 +1643,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16341643
}
16351644
}
16361645

1646+
fn check_expr_unsafe_binder_cast(
1647+
&self,
1648+
_kind: hir::UnsafeBinderCastKind,
1649+
expr: &'tcx hir::Expr<'tcx>,
1650+
_hir_ty: Option<&'tcx hir::Ty<'tcx>>,
1651+
_expected: Expectation<'tcx>,
1652+
) -> Ty<'tcx> {
1653+
let guar =
1654+
self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
1655+
Ty::new_error(self.tcx, guar)
1656+
}
1657+
16371658
fn check_expr_array(
16381659
&self,
16391660
args: &'tcx [hir::Expr<'tcx>],

Diff for: compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+7
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
341341
self.walk_expr(subexpr)?;
342342
}
343343

344+
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
345+
self.walk_expr(subexpr)?;
346+
}
347+
344348
hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
345349
// *base
346350
self.walk_expr(base)?;
@@ -1360,7 +1364,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
13601364
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
13611365
}
13621366

1367+
// both type ascription and unsafe binder casts don't affect
1368+
// the place-ness of the subexpression.
13631369
hir::ExprKind::Type(e, _) => self.cat_expr(e),
1370+
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
13641371

13651372
hir::ExprKind::AddrOf(..)
13661373
| hir::ExprKind::Call(..)

Diff for: compiler/rustc_lint/src/dangling.rs

+2
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
192192
| ExprKind::DropTemps(..)
193193
| ExprKind::Let(..) => false,
194194

195+
ExprKind::UnsafeBinderCast(..) => false,
196+
195197
// Not applicable
196198
ExprKind::Type(..) | ExprKind::Err(..) => false,
197199
}

Diff for: compiler/rustc_lint/src/if_let_rescope.rs

+1
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
422422
hir::ExprKind::Unary(_, expr)
423423
| hir::ExprKind::Cast(expr, _)
424424
| hir::ExprKind::Type(expr, _)
425+
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
425426
| hir::ExprKind::Yield(expr, _)
426427
| hir::ExprKind::AddrOf(_, _, expr)
427428
| hir::ExprKind::Match(expr, _, _)

Diff for: compiler/rustc_mir_build/src/thir/cx/expr.rs

+5
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,11 @@ impl<'tcx> Cx<'tcx> {
915915
}
916916
}
917917
}
918+
919+
hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
920+
unreachable!("unsafe binders are not yet implemented")
921+
}
922+
918923
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
919924
hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
920925
hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },

Diff for: compiler/rustc_parse/src/parser/expr.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_ast::visit::{Visitor, walk_expr};
1515
use rustc_ast::{
1616
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
1717
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
18-
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp,
18+
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
1919
};
2020
use rustc_ast_pretty::pprust;
2121
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -1931,6 +1931,12 @@ impl<'a> Parser<'a> {
19311931
Ok(match ident.name {
19321932
sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
19331933
sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
1934+
sym::wrap_binder => {
1935+
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
1936+
}
1937+
sym::unwrap_binder => {
1938+
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
1939+
}
19341940
_ => None,
19351941
})
19361942
})
@@ -2006,6 +2012,17 @@ impl<'a> Parser<'a> {
20062012
Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
20072013
}
20082014

2015+
pub(crate) fn parse_expr_unsafe_binder_cast(
2016+
&mut self,
2017+
lo: Span,
2018+
kind: UnsafeBinderCastKind,
2019+
) -> PResult<'a, P<Expr>> {
2020+
let expr = self.parse_expr()?;
2021+
let ty = if self.eat(&TokenKind::Comma) { Some(self.parse_ty()?) } else { None };
2022+
let span = lo.to(self.token.span);
2023+
Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
2024+
}
2025+
20092026
/// Returns a string literal if the next token is a string literal.
20102027
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
20112028
/// and returns `None` if the next token is not literal at all.
@@ -4019,7 +4036,9 @@ impl MutVisitor for CondChecker<'_> {
40194036
mut_visit::walk_expr(self, e);
40204037
self.forbid_let_reason = forbid_let_reason;
40214038
}
4022-
ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => {
4039+
ExprKind::Cast(ref mut op, _)
4040+
| ExprKind::Type(ref mut op, _)
4041+
| ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
40234042
let forbid_let_reason = self.forbid_let_reason;
40244043
self.forbid_let_reason = Some(OtherForbidden);
40254044
self.visit_expr(op);

0 commit comments

Comments
 (0)