Skip to content

Commit bfe01d2

Browse files
Implement MIR and drop semantics for unsafe binders
1 parent 3c1e750 commit bfe01d2

File tree

50 files changed

+538
-90
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+538
-90
lines changed

compiler/rustc_ast/src/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1655,7 +1655,7 @@ impl GenBlockKind {
16551655
}
16561656

16571657
/// Whether we're unwrapping or wrapping an unsafe binder
1658-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1658+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
16591659
#[derive(Encodable, Decodable, HashStable_Generic)]
16601660
pub enum UnsafeBinderCastKind {
16611661
// e.g. `&i32` -> `unsafe<'a> &'a i32`

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3976,7 +3976,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
39763976
ProjectionElem::ConstantIndex { .. }
39773977
| ProjectionElem::Subslice { .. }
39783978
| ProjectionElem::Subtype(_)
3979-
| ProjectionElem::Index(_) => kind,
3979+
| ProjectionElem::Index(_)
3980+
| ProjectionElem::UnsafeBinderCast(..) => kind,
39803981
},
39813982
place_ty.projection_ty(tcx, elem),
39823983
)

compiler/rustc_borrowck/src/diagnostics/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
243243
ProjectionElem::Downcast(..) => (),
244244
ProjectionElem::OpaqueCast(..) => (),
245245
ProjectionElem::Subtype(..) => (),
246+
ProjectionElem::UnsafeBinderCast(..) => (),
246247
ProjectionElem::Field(field, _ty) => {
247248
// FIXME(project-rfc_2229#36): print capture precisely here.
248249
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -323,9 +324,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
323324
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
324325
}
325326
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
326-
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
327-
PlaceTy::from_ty(*ty)
328-
}
327+
ProjectionElem::Subtype(ty)
328+
| ProjectionElem::OpaqueCast(ty)
329+
| ProjectionElem::UnsafeBinderCast(_, ty) => PlaceTy::from_ty(*ty),
329330
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
330331
},
331332
};

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
167167
| ProjectionElem::ConstantIndex { .. }
168168
| ProjectionElem::OpaqueCast { .. }
169169
| ProjectionElem::Subslice { .. }
170-
| ProjectionElem::Downcast(..),
170+
| ProjectionElem::Downcast(..)
171+
| ProjectionElem::UnsafeBinderCast(..),
171172
],
172173
} => bug!("Unexpected immutable place."),
173174
}

compiler/rustc_borrowck/src/lib.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1690,7 +1690,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
16901690
// So it's safe to skip these.
16911691
ProjectionElem::OpaqueCast(_)
16921692
| ProjectionElem::Subtype(_)
1693-
| ProjectionElem::Downcast(_, _) => (),
1693+
| ProjectionElem::Downcast(_, _)
1694+
| ProjectionElem::UnsafeBinderCast(_, _) => (),
16941695
}
16951696

16961697
place_ty = place_ty.projection_ty(tcx, elem);
@@ -1924,6 +1925,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
19241925
// FIXME: is this true even if P is an adt with a dtor?
19251926
{ }
19261927

1928+
ProjectionElem::UnsafeBinderCast(..) => {
1929+
check_parent_of_field(self, location, place_base, span, state);
1930+
}
1931+
19271932
// assigning to (*P) requires P to be initialized
19281933
ProjectionElem::Deref => {
19291934
self.check_if_full_path_is_moved(
@@ -2304,7 +2309,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
23042309
| ProjectionElem::Subslice { .. }
23052310
| ProjectionElem::Subtype(..)
23062311
| ProjectionElem::OpaqueCast { .. }
2307-
| ProjectionElem::Downcast(..) => {
2312+
| ProjectionElem::Downcast(..)
2313+
| ProjectionElem::UnsafeBinderCast(..) => {
23082314
let upvar_field_projection = self.is_upvar_field_projection(place);
23092315
if let Some(field) = upvar_field_projection {
23102316
let upvar = &self.upvars[field.index()];

compiler/rustc_borrowck/src/places_conflict.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ fn place_components_conflict<'tcx>(
249249
| (ProjectionElem::Subslice { .. }, _, _)
250250
| (ProjectionElem::OpaqueCast { .. }, _, _)
251251
| (ProjectionElem::Subtype(_), _, _)
252-
| (ProjectionElem::Downcast { .. }, _, _) => {
252+
| (ProjectionElem::Downcast { .. }, _, _)
253+
| (ProjectionElem::UnsafeBinderCast(..), _, _) => {
253254
// Recursive case. This can still be disjoint on a
254255
// further iteration if this a shallow access and
255256
// there's a deref later on, e.g., a borrow
@@ -518,5 +519,9 @@ fn place_projection_conflict<'tcx>(
518519
pi1_elem,
519520
pi2_elem
520521
),
522+
523+
(ProjectionElem::UnsafeBinderCast(..), _) => {
524+
todo!()
525+
}
521526
}
522527
}

compiler/rustc_borrowck/src/prefixes.rs

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
6666
self.next = Some(cursor_base);
6767
return Some(cursor);
6868
}
69+
ProjectionElem::UnsafeBinderCast(..) => {
70+
self.next = Some(cursor_base);
71+
return Some(cursor);
72+
}
6973
ProjectionElem::Downcast(..)
7074
| ProjectionElem::Subslice { .. }
7175
| ProjectionElem::OpaqueCast { .. }

compiler/rustc_borrowck/src/type_check/mod.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,46 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
284284
)
285285
.unwrap();
286286
}
287+
ProjectionElem::UnsafeBinderCast(kind, ty) => match kind {
288+
hir::UnsafeBinderCastKind::Wrap => {
289+
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
290+
unreachable!();
291+
};
292+
let expected_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars(
293+
self.body().source_info(location).span,
294+
BoundRegionConversionTime::HigherRankedType,
295+
binder_ty.into(),
296+
);
297+
self.typeck
298+
.relate_types(
299+
expected_ty,
300+
context.ambient_variance(),
301+
base_ty.ty,
302+
location.to_locations(),
303+
ConstraintCategory::TypeAnnotation,
304+
)
305+
.unwrap();
306+
}
307+
hir::UnsafeBinderCastKind::Unwrap => {
308+
let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else {
309+
unreachable!();
310+
};
311+
let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars(
312+
self.body().source_info(location).span,
313+
BoundRegionConversionTime::HigherRankedType,
314+
binder_ty.into(),
315+
);
316+
self.typeck
317+
.relate_types(
318+
ty,
319+
context.ambient_variance(),
320+
found_ty,
321+
location.to_locations(),
322+
ConstraintCategory::TypeAnnotation,
323+
)
324+
.unwrap();
325+
}
326+
},
287327
ProjectionElem::Subtype(_) => {
288328
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
289329
}
@@ -2413,7 +2453,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
24132453
| ProjectionElem::OpaqueCast(..)
24142454
| ProjectionElem::Index(..)
24152455
| ProjectionElem::ConstantIndex { .. }
2416-
| ProjectionElem::Subslice { .. } => {
2456+
| ProjectionElem::Subslice { .. }
2457+
| ProjectionElem::UnsafeBinderCast(..) => {
24172458
// other field access
24182459
}
24192460
ProjectionElem::Subtype(_) => {

compiler/rustc_codegen_cranelift/src/base.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,9 @@ pub(crate) fn codegen_place<'tcx>(
977977
cplace = cplace.place_deref(fx);
978978
}
979979
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
980-
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)),
980+
PlaceElem::Subtype(ty) | PlaceElem::UnsafeBinderCast(_, ty) => {
981+
cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
982+
}
981983
PlaceElem::Field(field, _ty) => {
982984
cplace = cplace.place_field(fx, field);
983985
}

compiler/rustc_codegen_ssa/src/mir/place.rs

+3
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
502502
bug!("encountered OpaqueCast({ty}) in codegen")
503503
}
504504
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
505+
mir::ProjectionElem::UnsafeBinderCast(_, ty) => {
506+
cg_base.project_type(bx, self.monomorphize(ty))
507+
}
505508
mir::ProjectionElem::Index(index) => {
506509
let index = &mir::Operand::Copy(mir::Place::from(index));
507510
let index = self.codegen_operand(bx, index);

compiler/rustc_const_eval/src/check_consts/qualifs.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ where
295295
| ProjectionElem::ConstantIndex { .. }
296296
| ProjectionElem::Subslice { .. }
297297
| ProjectionElem::Downcast(_, _)
298-
| ProjectionElem::Index(_) => {}
298+
| ProjectionElem::Index(_)
299+
| ProjectionElem::UnsafeBinderCast(..) => {}
299300
}
300301

301302
let base_ty = place_base.ty(cx.body, cx.tcx);

compiler/rustc_const_eval/src/interpret/projection.rs

+1
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ where
381381
OpaqueCast(ty) => {
382382
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
383383
}
384+
UnsafeBinderCast(_, target) => base.transmute(self.layout_of(target)?, self)?,
384385
// We don't want anything happening here, this is here as a dummy.
385386
Subtype(_) => base.transmute(base.layout(), self)?,
386387
Field(field, _) => self.project_field(base, field.index())?,

compiler/rustc_hir_typeck/src/expr.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1655,8 +1655,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16551655
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
16561656
expected: Expectation<'tcx>,
16571657
) -> Ty<'tcx> {
1658-
self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
1659-
16601658
match kind {
16611659
hir::UnsafeBinderCastKind::Wrap => {
16621660
let ascribed_ty =

compiler/rustc_middle/src/mir/pretty.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,14 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
12861286
ProjectionElem::Index(_)
12871287
| ProjectionElem::ConstantIndex { .. }
12881288
| ProjectionElem::Subslice { .. } => {}
1289+
ProjectionElem::UnsafeBinderCast(kind, _) => match kind {
1290+
hir::UnsafeBinderCastKind::Wrap => {
1291+
write!(fmt, "wrap_unsafe_binder!(")?;
1292+
}
1293+
rustc_ast::UnsafeBinderCastKind::Unwrap => {
1294+
write!(fmt, "unwrap_unsafe_binder!(")?;
1295+
}
1296+
},
12891297
}
12901298
}
12911299

@@ -1334,6 +1342,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
13341342
ProjectionElem::Subslice { from, to, from_end: false } => {
13351343
write!(fmt, "[{from:?}..{to:?}]")?;
13361344
}
1345+
ProjectionElem::UnsafeBinderCast(_, ty) => {
1346+
write!(fmt, "; {ty})")?;
1347+
}
13371348
}
13381349
}
13391350

compiler/rustc_middle/src/mir/statement.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ impl<V, T> ProjectionElem<V, T> {
6262
| Self::Subtype(_)
6363
| Self::ConstantIndex { .. }
6464
| Self::Subslice { .. }
65-
| Self::Downcast(_, _) => false,
65+
| Self::Downcast(_, _)
66+
| Self::UnsafeBinderCast(..) => false,
6667
}
6768
}
6869

@@ -76,7 +77,8 @@ impl<V, T> ProjectionElem<V, T> {
7677
| Self::Subtype(_)
7778
| Self::ConstantIndex { .. }
7879
| Self::Subslice { .. }
79-
| Self::Downcast(_, _) => true,
80+
| Self::Downcast(_, _)
81+
| Self::UnsafeBinderCast(..) => true,
8082
}
8183
}
8284

@@ -102,6 +104,9 @@ impl<V, T> ProjectionElem<V, T> {
102104
| Self::Subtype(_)
103105
| Self::OpaqueCast(_)
104106
| Self::Subslice { .. } => false,
107+
108+
// FIXME(unsafe_binders): Figure this out.
109+
Self::UnsafeBinderCast(..) => false,
105110
}
106111
}
107112
}

compiler/rustc_middle/src/mir/syntax.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
use rustc_abi::{FieldIdx, VariantIdx};
77
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability};
88
use rustc_data_structures::packed::Pu128;
9-
use rustc_hir::CoroutineKind;
109
use rustc_hir::def_id::DefId;
10+
use rustc_hir::{CoroutineKind, UnsafeBinderCastKind};
1111
use rustc_index::IndexVec;
1212
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1313
use rustc_span::def_id::LocalDefId;
@@ -1215,6 +1215,8 @@ pub enum ProjectionElem<V, T> {
12151215
/// requiring an intermediate variable.
12161216
OpaqueCast(T),
12171217

1218+
UnsafeBinderCast(UnsafeBinderCastKind, T),
1219+
12181220
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
12191221
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
12201222
/// explicit during optimizations and codegen.

compiler/rustc_middle/src/mir/tcx.rs

+5
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ impl<'tcx> PlaceTy<'tcx> {
146146
ProjectionElem::Subtype(ty) => {
147147
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
148148
}
149+
150+
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
151+
ProjectionElem::UnsafeBinderCast(_, ty) => {
152+
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
153+
}
149154
};
150155
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
151156
answer

compiler/rustc_middle/src/mir/type_foldable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! `TypeFoldable` implementations for MIR types
22
33
use rustc_ast::InlineAsmTemplatePiece;
4+
use rustc_hir::UnsafeBinderCastKind;
45
use rustc_hir::def_id::LocalDefId;
56

67
use super::*;
@@ -20,6 +21,7 @@ TrivialTypeTraversalImpls! {
2021
SwitchTargets,
2122
CoroutineKind,
2223
CoroutineSavedLocal,
24+
UnsafeBinderCastKind,
2325
}
2426

2527
TrivialTypeTraversalImpls! {

compiler/rustc_middle/src/mir/visit.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,15 @@ macro_rules! visit_place_fns {
11401140
self.visit_ty(&mut new_ty, TyContext::Location(location));
11411141
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
11421142
}
1143+
PlaceElem::UnsafeBinderCast(kind, ty) => {
1144+
let mut new_ty = ty;
1145+
self.visit_ty(&mut new_ty, TyContext::Location(location));
1146+
if ty != new_ty {
1147+
Some(PlaceElem::UnsafeBinderCast(kind, new_ty))
1148+
} else {
1149+
None
1150+
}
1151+
}
11431152
PlaceElem::Deref
11441153
| PlaceElem::ConstantIndex { .. }
11451154
| PlaceElem::Subslice { .. }
@@ -1208,7 +1217,8 @@ macro_rules! visit_place_fns {
12081217
match elem {
12091218
ProjectionElem::OpaqueCast(ty)
12101219
| ProjectionElem::Subtype(ty)
1211-
| ProjectionElem::Field(_, ty) => {
1220+
| ProjectionElem::Field(_, ty)
1221+
| ProjectionElem::UnsafeBinderCast(_, ty) => {
12121222
self.visit_ty(ty, TyContext::Location(location));
12131223
}
12141224
ProjectionElem::Index(local) => {

compiler/rustc_middle/src/thir.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_abi::{FieldIdx, Integer, Size, VariantIdx};
1616
use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece};
1717
use rustc_hir as hir;
1818
use rustc_hir::def_id::DefId;
19-
use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd};
19+
use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd, UnsafeBinderCastKind};
2020
use rustc_index::{IndexVec, newtype_index};
2121
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable};
2222
use rustc_middle::middle::region;
@@ -489,6 +489,16 @@ pub enum ExprKind<'tcx> {
489489
user_ty: UserTy<'tcx>,
490490
user_ty_span: Span,
491491
},
492+
/// An unsafe binder cast on a place, e.g. `unwrap_unsafe_binder!(x)`.
493+
PlaceUnsafeBinderCast {
494+
kind: UnsafeBinderCastKind,
495+
source: ExprId,
496+
},
497+
/// An unsafe binder cast on a value, e.g. `wrap_unsafe_binder!(1; unsafe<> i32)`.
498+
ValueUnsafeBinderCast {
499+
kind: UnsafeBinderCastKind,
500+
source: ExprId,
501+
},
492502
/// A closure definition.
493503
Closure(Box<ClosureExpr<'tcx>>),
494504
/// A literal.

compiler/rustc_middle/src/thir/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
136136
| ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
137137
visitor.visit_expr(&visitor.thir()[source])
138138
}
139+
PlaceUnsafeBinderCast { source, kind: _ } | ValueUnsafeBinderCast { source, kind: _ } => {
140+
visitor.visit_expr(&visitor.thir()[source])
141+
}
139142
Closure(box ClosureExpr {
140143
closure_id: _,
141144
args: _,

compiler/rustc_mir_build/messages.ftl

+12
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,18 @@ mir_build_unreachable_pattern = unreachable pattern
370370
.unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings
371371
.suggestion = remove the match arm
372372
373+
mir_build_unsafe_binder_cast_requires_unsafe =
374+
unsafe binder cast is unsafe and requires unsafe block
375+
.label = unsafe binder cast
376+
.note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
377+
information that may be required to uphold safety guarantees of a type
378+
379+
mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
380+
unsafe binder cast is unsafe and requires unsafe block or unsafe fn
381+
.label = unsafe binder cast
382+
.note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
383+
information that may be required to uphold safety guarantees of a type
384+
373385
mir_build_unsafe_field_requires_unsafe =
374386
use of unsafe field is unsafe and requires unsafe block
375387
.note = unsafe fields may carry library invariants

0 commit comments

Comments
 (0)