Skip to content

Commit 3ccd62d

Browse files
Implement MIR projection for unsafe binder cast
1 parent ce76ef3 commit 3ccd62d

File tree

24 files changed

+138
-28
lines changed

24 files changed

+138
-28
lines changed

compiler/rustc_ast/src/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1608,7 +1608,7 @@ impl GenBlockKind {
16081608
}
16091609

16101610
/// Whether we're unwrapping or wrapping an unsafe binder
1611-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1611+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
16121612
#[derive(Encodable, Decodable, HashStable_Generic)]
16131613
pub enum UnsafeBinderCastKind {
16141614
// 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
@@ -3950,7 +3950,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
39503950
ProjectionElem::ConstantIndex { .. }
39513951
| ProjectionElem::Subslice { .. }
39523952
| ProjectionElem::Subtype(_)
3953-
| ProjectionElem::Index(_) => kind,
3953+
| ProjectionElem::Index(_)
3954+
| ProjectionElem::UnsafeBinderCast(..) => kind,
39543955
},
39553956
place_ty.projection_ty(tcx, elem),
39563957
)

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
@@ -168,7 +168,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
168168
| ProjectionElem::ConstantIndex { .. }
169169
| ProjectionElem::OpaqueCast { .. }
170170
| ProjectionElem::Subslice { .. }
171-
| ProjectionElem::Downcast(..),
171+
| ProjectionElem::Downcast(..)
172+
| ProjectionElem::UnsafeBinderCast(..),
172173
],
173174
} => bug!("Unexpected immutable place."),
174175
}

compiler/rustc_borrowck/src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1724,7 +1724,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
17241724
// So it's safe to skip these.
17251725
ProjectionElem::OpaqueCast(_)
17261726
| ProjectionElem::Subtype(_)
1727-
| ProjectionElem::Downcast(_, _) => (),
1727+
| ProjectionElem::Downcast(_, _)
1728+
| ProjectionElem::UnsafeBinderCast(_, _) => (),
17281729
}
17291730

17301731
place_ty = place_ty.projection_ty(tcx, elem);
@@ -1952,7 +1953,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
19521953
ProjectionElem::OpaqueCast(_) |
19531954
ProjectionElem::ConstantIndex { .. } |
19541955
// assigning to P[i] requires P to be valid.
1955-
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
1956+
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) |
1957+
ProjectionElem::UnsafeBinderCast(..) =>
19561958
// assigning to (P->variant) is okay if assigning to `P` is okay
19571959
//
19581960
// FIXME: is this true even if P is an adt with a dtor?
@@ -2341,7 +2343,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
23412343
| ProjectionElem::Subslice { .. }
23422344
| ProjectionElem::Subtype(..)
23432345
| ProjectionElem::OpaqueCast { .. }
2344-
| ProjectionElem::Downcast(..) => {
2346+
| ProjectionElem::Downcast(..)
2347+
| ProjectionElem::UnsafeBinderCast(..) => {
23452348
let upvar_field_projection = self.is_upvar_field_projection(place);
23462349
if let Some(field) = upvar_field_projection {
23472350
let upvar = &self.upvars[field.index()];

compiler/rustc_borrowck/src/places_conflict.rs

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

compiler/rustc_borrowck/src/prefixes.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
7070
| ProjectionElem::Subslice { .. }
7171
| ProjectionElem::OpaqueCast { .. }
7272
| ProjectionElem::ConstantIndex { .. }
73-
| ProjectionElem::Index(_) => {
73+
| ProjectionElem::Index(_)
74+
| ProjectionElem::UnsafeBinderCast(..) => {
7475
cursor = cursor_base;
7576
continue 'cursor;
7677
}

compiler/rustc_borrowck/src/type_check/mod.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,48 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
742742
.unwrap();
743743
PlaceTy::from_ty(ty)
744744
}
745+
ProjectionElem::UnsafeBinderCast(kind, ty) => match kind {
746+
hir::UnsafeBinderCastKind::Wrap => {
747+
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
748+
bug!();
749+
};
750+
let expected_ty = self.cx.infcx.instantiate_binder_with_fresh_vars(
751+
self.body().source_info(location).span,
752+
BoundRegionConversionTime::HigherRankedType,
753+
binder_ty.into(),
754+
);
755+
self.cx
756+
.relate_types(
757+
expected_ty,
758+
self.get_ambient_variance(context),
759+
base_ty,
760+
location.to_locations(),
761+
ConstraintCategory::TypeAnnotation,
762+
)
763+
.unwrap();
764+
PlaceTy::from_ty(ty)
765+
}
766+
hir::UnsafeBinderCastKind::Unwrap => {
767+
let ty::UnsafeBinder(binder_ty) = *base_ty.kind() else {
768+
bug!();
769+
};
770+
let found_ty = self.cx.infcx.instantiate_binder_with_fresh_vars(
771+
self.body().source_info(location).span,
772+
BoundRegionConversionTime::HigherRankedType,
773+
binder_ty.into(),
774+
);
775+
self.cx
776+
.relate_types(
777+
ty,
778+
self.get_ambient_variance(context),
779+
found_ty,
780+
location.to_locations(),
781+
ConstraintCategory::TypeAnnotation,
782+
)
783+
.unwrap();
784+
PlaceTy::from_ty(ty)
785+
}
786+
},
745787
}
746788
}
747789

@@ -2744,7 +2786,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27442786
| ProjectionElem::OpaqueCast(..)
27452787
| ProjectionElem::Index(..)
27462788
| ProjectionElem::ConstantIndex { .. }
2747-
| ProjectionElem::Subslice { .. } => {
2789+
| ProjectionElem::Subslice { .. }
2790+
| ProjectionElem::UnsafeBinderCast(..) => {
27482791
// other field access
27492792
}
27502793
ProjectionElem::Subtype(_) => {

compiler/rustc_codegen_ssa/src/mir/place.rs

+3
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
497497
bug!("encountered OpaqueCast({ty}) in codegen")
498498
}
499499
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
500+
mir::ProjectionElem::UnsafeBinderCast(_, ty) => {
501+
cg_base.project_type(bx, self.monomorphize(ty))
502+
}
500503
mir::ProjectionElem::Index(index) => {
501504
let index = &mir::Operand::Copy(mir::Place::from(index));
502505
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
@@ -337,7 +337,8 @@ where
337337
| ProjectionElem::ConstantIndex { .. }
338338
| ProjectionElem::Subslice { .. }
339339
| ProjectionElem::Downcast(_, _)
340-
| ProjectionElem::Index(_) => {}
340+
| ProjectionElem::Index(_)
341+
| ProjectionElem::UnsafeBinderCast(..) => {}
341342
}
342343

343344
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
@@ -371,6 +371,7 @@ where
371371
OpaqueCast(ty) => {
372372
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
373373
}
374+
UnsafeBinderCast(_, target) => base.transmute(self.layout_of(target)?, self)?,
374375
// We don't want anything happening here, this is here as a dummy.
375376
Subtype(_) => base.transmute(base.layout(), self)?,
376377
Field(field, _) => self.project_field(base, field.index())?,

compiler/rustc_middle/src/mir/pretty.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,14 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
12711271
ProjectionElem::Index(_)
12721272
| ProjectionElem::ConstantIndex { .. }
12731273
| ProjectionElem::Subslice { .. } => {}
1274+
ProjectionElem::UnsafeBinderCast(kind, _) => match kind {
1275+
hir::UnsafeBinderCastKind::Wrap => {
1276+
write!(fmt, "wrap_unsafe_binder!(")?;
1277+
}
1278+
rustc_ast::UnsafeBinderCastKind::Unwrap => {
1279+
write!(fmt, "unwrap_unsafe_binder!(")?;
1280+
}
1281+
},
12741282
}
12751283
}
12761284

@@ -1319,6 +1327,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
13191327
ProjectionElem::Subslice { from, to, from_end: false } => {
13201328
write!(fmt, "[{from:?}..{to:?}]")?;
13211329
}
1330+
ProjectionElem::UnsafeBinderCast(_, ty) => {
1331+
write!(fmt, "; {ty})")?;
1332+
}
13221333
}
13231334
}
13241335

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
@@ -5,8 +5,8 @@
55
66
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability};
77
use rustc_data_structures::packed::Pu128;
8-
use rustc_hir::CoroutineKind;
98
use rustc_hir::def_id::DefId;
9+
use rustc_hir::{CoroutineKind, UnsafeBinderCastKind};
1010
use rustc_index::IndexVec;
1111
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1212
use rustc_span::Span;
@@ -1166,6 +1166,8 @@ pub enum ProjectionElem<V, T> {
11661166
/// requiring an intermediate variable.
11671167
OpaqueCast(T),
11681168

1169+
UnsafeBinderCast(UnsafeBinderCastKind, T),
1170+
11691171
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
11701172
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
11711173
/// explicit during optimizations and codegen.

compiler/rustc_middle/src/mir/tcx.rs

+5
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ impl<'tcx> PlaceTy<'tcx> {
110110
ProjectionElem::Subtype(ty) => {
111111
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
112112
}
113+
114+
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
115+
ProjectionElem::UnsafeBinderCast(_, ty) => {
116+
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
117+
}
113118
};
114119
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
115120
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
@@ -1146,6 +1146,15 @@ macro_rules! visit_place_fns {
11461146
self.visit_ty(&mut new_ty, TyContext::Location(location));
11471147
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
11481148
}
1149+
PlaceElem::UnsafeBinderCast(kind, ty) => {
1150+
let mut new_ty = ty;
1151+
self.visit_ty(&mut new_ty, TyContext::Location(location));
1152+
if ty != new_ty {
1153+
Some(PlaceElem::UnsafeBinderCast(kind, new_ty))
1154+
} else {
1155+
None
1156+
}
1157+
}
11491158
PlaceElem::Deref
11501159
| PlaceElem::ConstantIndex { .. }
11511160
| PlaceElem::Subslice { .. }
@@ -1214,7 +1223,8 @@ macro_rules! visit_place_fns {
12141223
match elem {
12151224
ProjectionElem::OpaqueCast(ty)
12161225
| ProjectionElem::Subtype(ty)
1217-
| ProjectionElem::Field(_, ty) => {
1226+
| ProjectionElem::Field(_, ty)
1227+
| ProjectionElem::UnsafeBinderCast(_, ty) => {
12181228
self.visit_ty(ty, TyContext::Location(location));
12191229
}
12201230
ProjectionElem::Index(local) => {

compiler/rustc_mir_build/src/build/expr/as_place.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ fn convert_to_hir_projections_and_truncate_for_capture(
106106
ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
107107
ProjectionElem::Index(..)
108108
| ProjectionElem::ConstantIndex { .. }
109-
| ProjectionElem::Subslice { .. } => {
109+
| ProjectionElem::Subslice { .. }
110+
| ProjectionElem::UnsafeBinderCast(..) => {
110111
// We don't capture array-access projections.
111112
// We can stop here as arrays are captured completely.
112113
break;
@@ -522,20 +523,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
522523
block.and(PlaceBuilder::from(temp))
523524
}
524525

525-
ExprKind::PlaceUnsafeBinderCast { source, kind: _ } => {
526+
ExprKind::PlaceUnsafeBinderCast { source, kind } => {
526527
let place_builder = unpack!(
527528
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
528529
);
529-
// TODO: stick on a projection elem
530-
block.and(place_builder)
530+
block.and(place_builder.project(PlaceElem::UnsafeBinderCast(kind, expr.ty)))
531531
}
532-
ExprKind::ValueUnsafeBinderCast { source, kind: _ } => {
532+
ExprKind::ValueUnsafeBinderCast { source, kind } => {
533533
let source_expr = &this.thir[source];
534534
let temp = unpack!(
535535
block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
536536
);
537-
// TODO: stick on a projection elem
538-
block.and(PlaceBuilder::from(temp))
537+
block.and(
538+
PlaceBuilder::from(temp).project(PlaceElem::UnsafeBinderCast(kind, expr.ty)),
539+
)
539540
}
540541

541542
ExprKind::Array { .. }
@@ -728,7 +729,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
728729
| ProjectionElem::OpaqueCast(..)
729730
| ProjectionElem::Subtype(..)
730731
| ProjectionElem::ConstantIndex { .. }
731-
| ProjectionElem::Subslice { .. } => (),
732+
| ProjectionElem::Subslice { .. }
733+
| ProjectionElem::UnsafeBinderCast(..) => (),
732734
}
733735
}
734736
}

compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
5858
}
5959
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
6060
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty.lift()),
61+
ProjectionElem::UnsafeBinderCast(kind, ty) => {
62+
ProjectionElem::UnsafeBinderCast(kind, ty.lift())
63+
}
6164
}
6265
}
6366
}

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,12 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
236236
// `OpaqueCast`:Only transmutes the type, so no moves there.
237237
// `Downcast` :Only changes information about a `Place` without moving.
238238
// `Subtype` :Only transmutes the type, so moves.
239+
// `UnsafeBinderCast`: Only transmutes the place without moving.
239240
// So it's safe to skip these.
240241
ProjectionElem::OpaqueCast(_)
241242
| ProjectionElem::Subtype(_)
242-
| ProjectionElem::Downcast(_, _) => (),
243+
| ProjectionElem::Downcast(_, _)
244+
| ProjectionElem::UnsafeBinderCast(_, _) => (),
243245
}
244246
let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty;
245247
if !(self.filter)(elem_ty) {

0 commit comments

Comments
 (0)