Skip to content

Commit 59ed54f

Browse files
Implement MIR projection for unsafe binder cast
1 parent b1c170f commit 59ed54f

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
@@ -1662,7 +1662,7 @@ impl GenBlockKind {
16621662
}
16631663

16641664
/// Whether we're unwrapping or wrapping an unsafe binder
1665-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1665+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
16661666
#[derive(Encodable, Decodable, HashStable_Generic)]
16671667
pub enum UnsafeBinderCastKind {
16681668
// 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
@@ -3977,7 +3977,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
39773977
ProjectionElem::ConstantIndex { .. }
39783978
| ProjectionElem::Subslice { .. }
39793979
| ProjectionElem::Subtype(_)
3980-
| ProjectionElem::Index(_) => kind,
3980+
| ProjectionElem::Index(_)
3981+
| ProjectionElem::UnsafeBinderCast(..) => kind,
39813982
},
39823983
place_ty.projection_ty(tcx, elem),
39833984
)

compiler/rustc_borrowck/src/diagnostics/mod.rs

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

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
@@ -1716,7 +1716,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
17161716
// So it's safe to skip these.
17171717
ProjectionElem::OpaqueCast(_)
17181718
| ProjectionElem::Subtype(_)
1719-
| ProjectionElem::Downcast(_, _) => (),
1719+
| ProjectionElem::Downcast(_, _)
1720+
| ProjectionElem::UnsafeBinderCast(_, _) => (),
17201721
}
17211722

17221723
place_ty = place_ty.projection_ty(tcx, elem);
@@ -1944,7 +1945,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
19441945
ProjectionElem::OpaqueCast(_) |
19451946
ProjectionElem::ConstantIndex { .. } |
19461947
// assigning to P[i] requires P to be valid.
1947-
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
1948+
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) |
1949+
ProjectionElem::UnsafeBinderCast(..) =>
19481950
// assigning to (P->variant) is okay if assigning to `P` is okay
19491951
//
19501952
// FIXME: is this true even if P is an adt with a dtor?
@@ -2330,7 +2332,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
23302332
| ProjectionElem::Subslice { .. }
23312333
| ProjectionElem::Subtype(..)
23322334
| ProjectionElem::OpaqueCast { .. }
2333-
| ProjectionElem::Downcast(..) => {
2335+
| ProjectionElem::Downcast(..)
2336+
| ProjectionElem::UnsafeBinderCast(..) => {
23342337
let upvar_field_projection = self.is_upvar_field_projection(place);
23352338
if let Some(field) = upvar_field_projection {
23362339
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
}
7677
ProjectionElem::Subtype(..) => {

compiler/rustc_borrowck/src/type_check/mod.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,48 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
719719
.unwrap();
720720
PlaceTy::from_ty(ty)
721721
}
722+
ProjectionElem::UnsafeBinderCast(kind, ty) => match kind {
723+
hir::UnsafeBinderCastKind::Wrap => {
724+
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
725+
bug!();
726+
};
727+
let expected_ty = self.cx.infcx.instantiate_binder_with_fresh_vars(
728+
self.body().source_info(location).span,
729+
BoundRegionConversionTime::HigherRankedType,
730+
binder_ty.into(),
731+
);
732+
self.cx
733+
.relate_types(
734+
expected_ty,
735+
self.get_ambient_variance(context),
736+
base_ty,
737+
location.to_locations(),
738+
ConstraintCategory::TypeAnnotation,
739+
)
740+
.unwrap();
741+
PlaceTy::from_ty(ty)
742+
}
743+
hir::UnsafeBinderCastKind::Unwrap => {
744+
let ty::UnsafeBinder(binder_ty) = *base_ty.kind() else {
745+
bug!();
746+
};
747+
let found_ty = self.cx.infcx.instantiate_binder_with_fresh_vars(
748+
self.body().source_info(location).span,
749+
BoundRegionConversionTime::HigherRankedType,
750+
binder_ty.into(),
751+
);
752+
self.cx
753+
.relate_types(
754+
ty,
755+
self.get_ambient_variance(context),
756+
found_ty,
757+
location.to_locations(),
758+
ConstraintCategory::TypeAnnotation,
759+
)
760+
.unwrap();
761+
PlaceTy::from_ty(ty)
762+
}
763+
},
722764
}
723765
}
724766

@@ -2705,7 +2747,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27052747
| ProjectionElem::OpaqueCast(..)
27062748
| ProjectionElem::Index(..)
27072749
| ProjectionElem::ConstantIndex { .. }
2708-
| ProjectionElem::Subslice { .. } => {
2750+
| ProjectionElem::Subslice { .. }
2751+
| ProjectionElem::UnsafeBinderCast(..) => {
27092752
// other field access
27102753
}
27112754
ProjectionElem::Subtype(_) => {

compiler/rustc_codegen_ssa/src/mir/place.rs

+3
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
504504
bug!("encountered OpaqueCast({ty}) in codegen")
505505
}
506506
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
507+
mir::ProjectionElem::UnsafeBinderCast(_, ty) => {
508+
cg_base.project_type(bx, self.monomorphize(ty))
509+
}
507510
mir::ProjectionElem::Index(index) => {
508511
let index = &mir::Operand::Copy(mir::Place::from(index));
509512
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
@@ -297,7 +297,8 @@ where
297297
| ProjectionElem::ConstantIndex { .. }
298298
| ProjectionElem::Subslice { .. }
299299
| ProjectionElem::Downcast(_, _)
300-
| ProjectionElem::Index(_) => {}
300+
| ProjectionElem::Index(_)
301+
| ProjectionElem::UnsafeBinderCast(..) => {}
301302
}
302303

303304
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_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::Span;
@@ -1211,6 +1211,8 @@ pub enum ProjectionElem<V, T> {
12111211
/// requiring an intermediate variable.
12121212
OpaqueCast(T),
12131213

1214+
UnsafeBinderCast(UnsafeBinderCastKind, T),
1215+
12141216
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
12151217
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
12161218
/// explicit during optimizations and codegen.

compiler/rustc_middle/src/mir/tcx.rs

+5
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ impl<'tcx> PlaceTy<'tcx> {
111111
ProjectionElem::Subtype(ty) => {
112112
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
113113
}
114+
115+
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
116+
ProjectionElem::UnsafeBinderCast(_, ty) => {
117+
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
118+
}
114119
};
115120
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
116121
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
@@ -1148,6 +1148,15 @@ macro_rules! visit_place_fns {
11481148
self.visit_ty(&mut new_ty, TyContext::Location(location));
11491149
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
11501150
}
1151+
PlaceElem::UnsafeBinderCast(kind, ty) => {
1152+
let mut new_ty = ty;
1153+
self.visit_ty(&mut new_ty, TyContext::Location(location));
1154+
if ty != new_ty {
1155+
Some(PlaceElem::UnsafeBinderCast(kind, new_ty))
1156+
} else {
1157+
None
1158+
}
1159+
}
11511160
PlaceElem::Deref
11521161
| PlaceElem::ConstantIndex { .. }
11531162
| PlaceElem::Subslice { .. }
@@ -1216,7 +1225,8 @@ macro_rules! visit_place_fns {
12161225
match elem {
12171226
ProjectionElem::OpaqueCast(ty)
12181227
| ProjectionElem::Subtype(ty)
1219-
| ProjectionElem::Field(_, ty) => {
1228+
| ProjectionElem::Field(_, ty)
1229+
| ProjectionElem::UnsafeBinderCast(_, ty) => {
12201230
self.visit_ty(ty, TyContext::Location(location));
12211231
}
12221232
ProjectionElem::Index(local) => {

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

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

526-
ExprKind::PlaceUnsafeBinderCast { source, kind: _ } => {
527+
ExprKind::PlaceUnsafeBinderCast { source, kind } => {
527528
let place_builder = unpack!(
528529
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
529530
);
530-
// TODO: stick on a projection elem
531-
block.and(place_builder)
531+
block.and(place_builder.project(PlaceElem::UnsafeBinderCast(kind, expr.ty)))
532532
}
533-
ExprKind::ValueUnsafeBinderCast { source, kind: _ } => {
533+
ExprKind::ValueUnsafeBinderCast { source, kind } => {
534534
let source_expr = &this.thir[source];
535535
let temp = unpack!(
536536
block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
537537
);
538-
// TODO: stick on a projection elem
539-
block.and(PlaceBuilder::from(temp))
538+
block.and(
539+
PlaceBuilder::from(temp).project(PlaceElem::UnsafeBinderCast(kind, expr.ty)),
540+
)
540541
}
541542

542543
ExprKind::Array { .. }
@@ -729,7 +730,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
729730
| ProjectionElem::OpaqueCast(..)
730731
| ProjectionElem::Subtype(..)
731732
| ProjectionElem::ConstantIndex { .. }
732-
| ProjectionElem::Subslice { .. } => (),
733+
| ProjectionElem::Subslice { .. }
734+
| ProjectionElem::UnsafeBinderCast(..) => (),
733735
}
734736
}
735737
}

compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
3232
}
3333
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
3434
ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()),
35+
ProjectionElem::UnsafeBinderCast(kind, _ty) => {
36+
ProjectionElem::UnsafeBinderCast(kind, ())
37+
}
3538
}
3639
}
3740
}

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,12 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
229229
// `OpaqueCast`:Only transmutes the type, so no moves there.
230230
// `Downcast` :Only changes information about a `Place` without moving.
231231
// `Subtype` :Only transmutes the type, so moves.
232+
// `UnsafeBinderCast`: Only transmutes the place without moving.
232233
// So it's safe to skip these.
233234
ProjectionElem::OpaqueCast(_)
234235
| ProjectionElem::Subtype(_)
235-
| ProjectionElem::Downcast(_, _) => (),
236+
| ProjectionElem::Downcast(_, _)
237+
| ProjectionElem::UnsafeBinderCast(_, _) => (),
236238
}
237239
let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty;
238240
if !(self.filter)(elem_ty) {

0 commit comments

Comments
 (0)