Skip to content

Commit 99e5ad9

Browse files
Add unwrap_unsafe_binder and wrap_unsafe_binder macro operators
1 parent 25a754c commit 99e5ad9

File tree

32 files changed

+338
-20
lines changed

32 files changed

+338
-20
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,7 @@ impl Expr {
13281328
| ExprKind::Type(..)
13291329
| ExprKind::OffsetOf(..)
13301330
| ExprKind::FormatArgs(..)
1331+
| ExprKind::UnsafeBinderCast(..)
13311332
| ExprKind::MacCall(..) => ExprPrecedence::Mac,
13321333
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
13331334
}
@@ -1454,7 +1455,13 @@ pub enum ExprKind {
14541455
/// `'label: for await? pat in iter { block }`
14551456
///
14561457
/// This is desugared to a combination of `loop` and `match` expressions.
1457-
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
1458+
ForLoop {
1459+
pat: P<Pat>,
1460+
iter: P<Expr>,
1461+
body: P<Block>,
1462+
label: Option<Label>,
1463+
kind: ForLoopKind,
1464+
},
14581465
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
14591466
///
14601467
/// `'label: loop { block }`
@@ -1559,6 +1566,8 @@ pub enum ExprKind {
15591566
/// A `format_args!()` expression.
15601567
FormatArgs(P<FormatArgs>),
15611568

1569+
UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
1570+
15621571
/// Placeholder for an expression that wasn't syntactically well formed in some way.
15631572
Err(ErrorGuaranteed),
15641573

@@ -1597,6 +1606,16 @@ impl GenBlockKind {
15971606
}
15981607
}
15991608

1609+
/// Whether we're unwrapping or wrapping an unsafe binder
1610+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1611+
#[derive(Encodable, Decodable, HashStable_Generic)]
1612+
pub enum UnsafeBinderCastKind {
1613+
// e.g. `&i32` -> `unsafe<'a> &'a i32`
1614+
Wrap,
1615+
// e.g. `unsafe<'a> &'a i32` -> `&i32`
1616+
Unwrap,
1617+
}
1618+
16001619
/// The explicit `Self` type in a "qualified path". The actual
16011620
/// path, including the trait and the associated item, is stored
16021621
/// separately. `position` represents the index of the associated

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,6 +1620,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
16201620
ExprKind::TryBlock(body) => vis.visit_block(body),
16211621
ExprKind::Lit(_token) => {}
16221622
ExprKind::IncludedBytes(_bytes) => {}
1623+
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
1624+
vis.visit_expr(expr);
1625+
if let Some(ty) = ty {
1626+
vis.visit_ty(ty);
1627+
}
1628+
}
16231629
ExprKind::Err(_guar) => {}
16241630
ExprKind::Dummy => {}
16251631
}

compiler/rustc_ast/src/util/classify.rs

Lines changed: 2 additions & 0 deletions
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
}

compiler/rustc_ast/src/visit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
11871187
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
11881188
ExprKind::Lit(_token) => {}
11891189
ExprKind::IncludedBytes(_bytes) => {}
1190+
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
1191+
try_visit!(visitor.visit_expr(expr));
1192+
visit_opt!(visitor, visit_ty, ty);
1193+
}
11901194
ExprKind::Err(_guar) => {}
11911195
ExprKind::Dummy => {}
11921196
}

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
339339
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
340340
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
341341

342+
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
343+
*kind,
344+
self.lower_expr(expr),
345+
ty.as_ref().map(|ty| {
346+
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
347+
}),
348+
),
349+
342350
ExprKind::Dummy => {
343351
span_bug!(e.span, "lowered ExprKind::Dummy")
344352
}

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,25 @@ impl<'a> State<'a> {
726726
self.word_nbsp("try");
727727
self.print_block_with_attrs(blk, attrs)
728728
}
729+
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
730+
self.word("builtin # ");
731+
match kind {
732+
ast::UnsafeBinderCastKind::Wrap => self.word("wrap_unsafe_binder"),
733+
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_unsafe_binder"),
734+
}
735+
self.popen();
736+
self.ibox(0);
737+
self.print_expr(expr, FixupContext::default());
738+
739+
if let Some(ty) = ty {
740+
self.word(",");
741+
self.space();
742+
self.print_type(ty);
743+
}
744+
745+
self.end();
746+
self.pclose();
747+
}
729748
ast::ExprKind::Err(_) => {
730749
self.popen();
731750
self.word("/*ERROR*/");

compiler/rustc_builtin_macros/src/assert/context.rs

Lines changed: 2 additions & 1 deletion
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

compiler/rustc_hir/src/hir.rs

Lines changed: 14 additions & 5 deletions
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, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability,
11-
Mutability, UnOp,
11+
Mutability, UnOp, UnsafeBinderCastKind,
1212
};
1313
use rustc_data_structures::fingerprint::Fingerprint;
1414
use rustc_data_structures::sorted_map::SortedMap;
@@ -1747,9 +1747,10 @@ impl Expr<'_> {
17471747
ExprKind::Struct(..) => ExprPrecedence::Struct,
17481748
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
17491749
ExprKind::Yield(..) => ExprPrecedence::Yield,
1750-
ExprKind::Type(..) | ExprKind::InlineAsm(..) | ExprKind::OffsetOf(..) => {
1751-
ExprPrecedence::Mac
1752-
}
1750+
ExprKind::Type(..)
1751+
| ExprKind::InlineAsm(..)
1752+
| ExprKind::OffsetOf(..)
1753+
| ExprKind::UnsafeBinderCast(..) => ExprPrecedence::Mac,
17531754
ExprKind::Err(_) => ExprPrecedence::Err,
17541755
}
17551756
}
@@ -1777,6 +1778,9 @@ impl Expr<'_> {
17771778
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
17781779
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
17791780

1781+
// Unsafe binder cast preserves place-ness of the sub-expression.
1782+
ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
1783+
17801784
ExprKind::Unary(UnOp::Deref, _) => true,
17811785

17821786
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
@@ -1858,7 +1862,8 @@ impl Expr<'_> {
18581862
| ExprKind::Field(base, _)
18591863
| ExprKind::Index(base, _, _)
18601864
| ExprKind::AddrOf(.., base)
1861-
| ExprKind::Cast(base, _) => {
1865+
| ExprKind::Cast(base, _)
1866+
| ExprKind::UnsafeBinderCast(_, base, _) => {
18621867
// This isn't exactly true for `Index` and all `Unary`, but we are using this
18631868
// method exclusively for diagnostics and there's a *cultural* pressure against
18641869
// them being used only for its side-effects.
@@ -2115,6 +2120,10 @@ pub enum ExprKind<'hir> {
21152120
/// A suspension point for coroutines (i.e., `yield <expr>`).
21162121
Yield(&'hir Expr<'hir>, YieldSource),
21172122

2123+
/// Operators which can be used to interconvert `unsafe` binder types.
2124+
/// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
2125+
UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
2126+
21182127
/// A placeholder for an expression that wasn't syntactically well formed in some way.
21192128
Err(rustc_span::ErrorGuaranteed),
21202129
}

compiler/rustc_hir/src/intravisit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
862862
ExprKind::Yield(ref subexpression, _) => {
863863
try_visit!(visitor.visit_expr(subexpression));
864864
}
865+
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
866+
try_visit!(visitor.visit_expr(expr));
867+
visit_opt!(visitor, visit_ty, ty);
868+
}
865869
ExprKind::Lit(_) | ExprKind::Err(_) => {}
866870
}
867871
V::Result::output()

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,19 @@ impl<'a> State<'a> {
15371537

15381538
self.word(")");
15391539
}
1540+
hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
1541+
match kind {
1542+
hir::UnsafeBinderCastKind::Wrap => self.word("wrap_unsafe_binder!("),
1543+
hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_unsafe_binder!("),
1544+
}
1545+
self.print_expr(expr);
1546+
if let Some(ty) = ty {
1547+
self.word(",");
1548+
self.space();
1549+
self.print_type(ty);
1550+
}
1551+
self.word(")");
1552+
}
15401553
hir::ExprKind::Yield(expr, _) => {
15411554
self.word_space("yield");
15421555
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
340340
self.check_expr_index(base, idx, expr, brackets_span)
341341
}
342342
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
343-
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
343+
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
344+
self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
345+
}
346+
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
344347
}
345348
}
346349

@@ -1404,6 +1407,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14041407
}
14051408
}
14061409

1410+
fn check_expr_unsafe_binder_cast(
1411+
&self,
1412+
kind: hir::UnsafeBinderCastKind,
1413+
expr: &'tcx hir::Expr<'tcx>,
1414+
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
1415+
expected: Expectation<'tcx>,
1416+
) -> Ty<'tcx> {
1417+
match kind {
1418+
hir::UnsafeBinderCastKind::Wrap => {
1419+
let ascribed_ty =
1420+
hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
1421+
let expected_ty = expected.only_has_type(self);
1422+
let binder_ty = match (ascribed_ty, expected_ty) {
1423+
(Some(ascribed_ty), Some(expected_ty)) => {
1424+
self.demand_eqtype(expr.span, expected_ty, ascribed_ty);
1425+
expected_ty
1426+
}
1427+
(Some(ty), None) | (None, Some(ty)) => ty,
1428+
(None, None) => self.next_ty_var(expr.span),
1429+
};
1430+
1431+
// Unwrap the binder eagerly if we can use it to guide inference on
1432+
// the inner expr. If not, then we'll error *after* type checking.
1433+
let hint_ty = if let ty::UnsafeBinder(binder) =
1434+
*self.try_structurally_resolve_type(expr.span, binder_ty).kind()
1435+
{
1436+
self.instantiate_binder_with_fresh_vars(
1437+
expr.span,
1438+
infer::BoundRegionConversionTime::HigherRankedType,
1439+
binder.into(),
1440+
)
1441+
} else {
1442+
self.next_ty_var(expr.span)
1443+
};
1444+
1445+
self.check_expr_has_type_or_error(expr, hint_ty, |_| {});
1446+
1447+
let binder_ty = self.structurally_resolve_type(expr.span, binder_ty);
1448+
match *binder_ty.kind() {
1449+
ty::UnsafeBinder(..) => {
1450+
// Ok
1451+
}
1452+
_ => todo!(),
1453+
}
1454+
1455+
binder_ty
1456+
}
1457+
hir::UnsafeBinderCastKind::Unwrap => {
1458+
let ascribed_ty =
1459+
hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
1460+
let hint_ty = ascribed_ty.unwrap_or_else(|| self.next_ty_var(expr.span));
1461+
// FIXME(unsafe_binders): coerce here if needed?
1462+
let binder_ty = self.check_expr_has_type_or_error(expr, hint_ty, |_| {});
1463+
1464+
// Unwrap the binder. This will be ambiguous if it's an infer var, and will error
1465+
// if it's not an unsafe binder.
1466+
let binder_ty = self.structurally_resolve_type(expr.span, binder_ty);
1467+
match *binder_ty.kind() {
1468+
ty::UnsafeBinder(binder) => self.instantiate_binder_with_fresh_vars(
1469+
expr.span,
1470+
infer::BoundRegionConversionTime::HigherRankedType,
1471+
binder.into(),
1472+
),
1473+
_ => todo!(),
1474+
}
1475+
}
1476+
}
1477+
}
1478+
14071479
fn check_expr_array(
14081480
&self,
14091481
args: &'tcx [hir::Expr<'tcx>],

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
340340
self.walk_expr(subexpr)?;
341341
}
342342

343+
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
344+
self.walk_expr(subexpr)?;
345+
}
346+
343347
hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
344348
// *base
345349
self.walk_expr(base)?;
@@ -1342,7 +1346,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
13421346
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
13431347
}
13441348

1349+
// both type ascription and unsafe binder casts don't affect
1350+
// the place-ness of the subexpression.
13451351
hir::ExprKind::Type(e, _) => self.cat_expr(e),
1352+
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
13461353

13471354
hir::ExprKind::AddrOf(..)
13481355
| hir::ExprKind::Call(..)

compiler/rustc_lint/src/if_let_rescope.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
399399
hir::ExprKind::Unary(_, expr)
400400
| hir::ExprKind::Cast(expr, _)
401401
| hir::ExprKind::Type(expr, _)
402+
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
402403
| hir::ExprKind::Yield(expr, _)
403404
| hir::ExprKind::AddrOf(_, _, expr)
404405
| hir::ExprKind::Match(expr, _, _)

compiler/rustc_lint/src/tail_expr_drop_order.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> {
276276
ExprKind::MethodCall(_, _, _, _)
277277
| ExprKind::Call(_, _)
278278
| ExprKind::Type(_, _)
279+
| ExprKind::UnsafeBinderCast(_, _, _)
279280
| ExprKind::Tup(_)
280281
| ExprKind::Binary(_, _, _)
281282
| ExprKind::Unary(_, _)

compiler/rustc_middle/src/thir.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::ops::Index;
1515
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1616
use rustc_hir as hir;
1717
use rustc_hir::def_id::DefId;
18-
use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
18+
use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd, UnsafeBinderCastKind};
1919
use rustc_index::{newtype_index, IndexVec};
2020
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable};
2121
use rustc_middle::middle::region;
@@ -460,6 +460,16 @@ pub enum ExprKind<'tcx> {
460460
/// Type that the user gave to this expression
461461
user_ty: UserTy<'tcx>,
462462
},
463+
/// An unsafe binder cast on a place, e.g. `unwrap_unsafe_binder!(x)`.
464+
PlaceUnsafeBinderCast {
465+
kind: UnsafeBinderCastKind,
466+
source: ExprId,
467+
},
468+
/// An unsafe binder cast on a value, e.g. `wrap_unsafe_binder!(1; unsafe<> i32)`.
469+
ValueUnsafeBinderCast {
470+
kind: UnsafeBinderCastKind,
471+
source: ExprId,
472+
},
463473
/// A closure definition.
464474
Closure(Box<ClosureExpr<'tcx>>),
465475
/// A literal.

compiler/rustc_middle/src/thir/visit.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
132132
PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
133133
visitor.visit_expr(&visitor.thir()[source])
134134
}
135+
PlaceUnsafeBinderCast { source, kind: _ } | ValueUnsafeBinderCast { source, kind: _ } => {
136+
visitor.visit_expr(&visitor.thir()[source])
137+
}
135138
Closure(box ClosureExpr {
136139
closure_id: _,
137140
args: _,

0 commit comments

Comments
 (0)