Skip to content

Commit ce76ef3

Browse files
Add unwrap_unsafe_binder and wrap_unsafe_binder macro operators
1 parent 29fa325 commit ce76ef3

File tree

32 files changed

+337
-19
lines changed

32 files changed

+337
-19
lines changed

compiler/rustc_ast/src/ast.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,7 @@ impl Expr {
13291329
| ExprKind::Type(..)
13301330
| ExprKind::OffsetOf(..)
13311331
| ExprKind::FormatArgs(..)
1332+
| ExprKind::UnsafeBinderCast(..)
13321333
| ExprKind::MacCall(..) => ExprPrecedence::Mac,
13331334
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
13341335
}
@@ -1455,7 +1456,13 @@ pub enum ExprKind {
14551456
/// `'label: for await? pat in iter { block }`
14561457
///
14571458
/// This is desugared to a combination of `loop` and `match` expressions.
1458-
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
1459+
ForLoop {
1460+
pat: P<Pat>,
1461+
iter: P<Expr>,
1462+
body: P<Block>,
1463+
label: Option<Label>,
1464+
kind: ForLoopKind,
1465+
},
14591466
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
14601467
///
14611468
/// `'label: loop { block }`
@@ -1560,6 +1567,8 @@ pub enum ExprKind {
15601567
/// A `format_args!()` expression.
15611568
FormatArgs(P<FormatArgs>),
15621569

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

@@ -1598,6 +1607,16 @@ impl GenBlockKind {
15981607
}
15991608
}
16001609

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

compiler/rustc_ast/src/mut_visit.rs

+6
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

+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
}

compiler/rustc_ast/src/visit.rs

+4
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

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

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

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

+19
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

+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

compiler/rustc_hir/src/hir.rs

+14-5
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;
@@ -1755,9 +1755,10 @@ impl Expr<'_> {
17551755
ExprKind::Struct(..) => ExprPrecedence::Struct,
17561756
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
17571757
ExprKind::Yield(..) => ExprPrecedence::Yield,
1758-
ExprKind::Type(..) | ExprKind::InlineAsm(..) | ExprKind::OffsetOf(..) => {
1759-
ExprPrecedence::Mac
1760-
}
1758+
ExprKind::Type(..)
1759+
| ExprKind::InlineAsm(..)
1760+
| ExprKind::OffsetOf(..)
1761+
| ExprKind::UnsafeBinderCast(..) => ExprPrecedence::Mac,
17611762
ExprKind::Err(_) => ExprPrecedence::Err,
17621763
}
17631764
}
@@ -1785,6 +1786,9 @@ impl Expr<'_> {
17851786
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
17861787
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
17871788

1789+
// Unsafe binder cast preserves place-ness of the sub-expression.
1790+
ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
1791+
17881792
ExprKind::Unary(UnOp::Deref, _) => true,
17891793

17901794
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
@@ -1866,7 +1870,8 @@ impl Expr<'_> {
18661870
| ExprKind::Field(base, _)
18671871
| ExprKind::Index(base, _, _)
18681872
| ExprKind::AddrOf(.., base)
1869-
| ExprKind::Cast(base, _) => {
1873+
| ExprKind::Cast(base, _)
1874+
| ExprKind::UnsafeBinderCast(_, base, _) => {
18701875
// This isn't exactly true for `Index` and all `Unary`, but we are using this
18711876
// method exclusively for diagnostics and there's a *cultural* pressure against
18721877
// them being used only for its side-effects.
@@ -2123,6 +2128,10 @@ pub enum ExprKind<'hir> {
21232128
/// A suspension point for coroutines (i.e., `yield <expr>`).
21242129
Yield(&'hir Expr<'hir>, YieldSource),
21252130

2131+
/// Operators which can be used to interconvert `unsafe` binder types.
2132+
/// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
2133+
UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
2134+
21262135
/// A placeholder for an expression that wasn't syntactically well formed in some way.
21272136
Err(rustc_span::ErrorGuaranteed),
21282137
}

compiler/rustc_hir/src/intravisit.rs

+4
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

+13
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

+73-1
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

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

345+
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
346+
self.walk_expr(subexpr)?;
347+
}
348+
345349
hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
346350
// *base
347351
self.walk_expr(base)?;
@@ -1355,7 +1359,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
13551359
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
13561360
}
13571361

1362+
// both type ascription and unsafe binder casts don't affect
1363+
// the place-ness of the subexpression.
13581364
hir::ExprKind::Type(e, _) => self.cat_expr(e),
1365+
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
13591366

13601367
hir::ExprKind::AddrOf(..)
13611368
| hir::ExprKind::Call(..)

compiler/rustc_lint/src/if_let_rescope.rs

+1
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
394394
hir::ExprKind::Unary(_, expr)
395395
| hir::ExprKind::Cast(expr, _)
396396
| hir::ExprKind::Type(expr, _)
397+
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
397398
| hir::ExprKind::Yield(expr, _)
398399
| hir::ExprKind::AddrOf(_, _, expr)
399400
| hir::ExprKind::Match(expr, _, _)

compiler/rustc_lint/src/tail_expr_drop_order.rs

+1
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

+11-1
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::{IndexVec, newtype_index};
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

+3
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)