Skip to content

Commit e4a4137

Browse files
Implement MIR projection for unsafe binder cast
1 parent 99e5ad9 commit e4a4137

File tree

24 files changed

+138
-28
lines changed

24 files changed

+138
-28
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1607,7 +1607,7 @@ impl GenBlockKind {
16071607
}
16081608

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

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

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

Lines changed: 4 additions & 3 deletions
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

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
17281728
// So it's safe to skip these.
17291729
ProjectionElem::OpaqueCast(_)
17301730
| ProjectionElem::Subtype(_)
1731-
| ProjectionElem::Downcast(_, _) => (),
1731+
| ProjectionElem::Downcast(_, _)
1732+
| ProjectionElem::UnsafeBinderCast(_, _) => (),
17321733
}
17331734

17341735
place_ty = place_ty.projection_ty(tcx, elem);
@@ -1956,7 +1957,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
19561957
ProjectionElem::OpaqueCast(_) |
19571958
ProjectionElem::ConstantIndex { .. } |
19581959
// assigning to P[i] requires P to be valid.
1959-
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
1960+
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) |
1961+
ProjectionElem::UnsafeBinderCast(..) =>
19601962
// assigning to (P->variant) is okay if assigning to `P` is okay
19611963
//
19621964
// FIXME: is this true even if P is an adt with a dtor?
@@ -2345,7 +2347,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
23452347
| ProjectionElem::Subslice { .. }
23462348
| ProjectionElem::Subtype(..)
23472349
| ProjectionElem::OpaqueCast { .. }
2348-
| ProjectionElem::Downcast(..) => {
2350+
| ProjectionElem::Downcast(..)
2351+
| ProjectionElem::UnsafeBinderCast(..) => {
23492352
let upvar_field_projection = self.is_upvar_field_projection(place);
23502353
if let Some(field) = upvar_field_projection {
23512354
let upvar = &self.upvars[field.index()];

compiler/rustc_borrowck/src/places_conflict.rs

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

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

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

@@ -2746,7 +2788,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27462788
| ProjectionElem::OpaqueCast(..)
27472789
| ProjectionElem::Index(..)
27482790
| ProjectionElem::ConstantIndex { .. }
2749-
| ProjectionElem::Subslice { .. } => {
2791+
| ProjectionElem::Subslice { .. }
2792+
| ProjectionElem::UnsafeBinderCast(..) => {
27502793
// other field access
27512794
}
27522795
ProjectionElem::Subtype(_) => {

compiler/rustc_codegen_ssa/src/mir/place.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
498498
bug!("encountered OpaqueCast({ty}) in codegen")
499499
}
500500
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
501+
mir::ProjectionElem::UnsafeBinderCast(_, ty) => {
502+
cg_base.project_type(bx, self.monomorphize(ty))
503+
}
501504
mir::ProjectionElem::Index(index) => {
502505
let index = &mir::Operand::Copy(mir::Place::from(index));
503506
let index = self.codegen_operand(bx, index);

compiler/rustc_const_eval/src/check_consts/qualifs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,8 @@ where
341341
| ProjectionElem::ConstantIndex { .. }
342342
| ProjectionElem::Subslice { .. }
343343
| ProjectionElem::Downcast(_, _)
344-
| ProjectionElem::Index(_) => {}
344+
| ProjectionElem::Index(_)
345+
| ProjectionElem::UnsafeBinderCast(..) => {}
345346
}
346347

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

compiler/rustc_const_eval/src/interpret/projection.rs

Lines changed: 1 addition & 0 deletions
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

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

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability};
77
use rustc_data_structures::packed::Pu128;
88
use rustc_hir::def_id::DefId;
9-
use rustc_hir::CoroutineKind;
9+
use rustc_hir::{CoroutineKind, UnsafeBinderCastKind};
1010
use rustc_index::IndexVec;
1111
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1212
use rustc_span::def_id::LocalDefId;
@@ -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

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use rustc_ast::InlineAsmTemplatePiece;
44
use rustc_hir::def_id::LocalDefId;
5+
use rustc_hir::UnsafeBinderCastKind;
56

67
use super::*;
78

@@ -20,6 +21,7 @@ TrivialTypeTraversalImpls! {
2021
SwitchTargets,
2122
CoroutineKind,
2223
CoroutineSavedLocal,
24+
UnsafeBinderCastKind,
2325
}
2426

2527
TrivialTypeTraversalImpls! {

compiler/rustc_middle/src/mir/visit.rs

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

Lines changed: 10 additions & 8 deletions
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;
@@ -528,20 +529,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
528529
block.and(PlaceBuilder::from(temp))
529530
}
530531

531-
ExprKind::PlaceUnsafeBinderCast { source, kind: _ } => {
532+
ExprKind::PlaceUnsafeBinderCast { source, kind } => {
532533
let place_builder = unpack!(
533534
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
534535
);
535-
// TODO: stick on a projection elem
536-
block.and(place_builder)
536+
block.and(place_builder.project(PlaceElem::UnsafeBinderCast(kind, expr.ty)))
537537
}
538-
ExprKind::ValueUnsafeBinderCast { source, kind: _ } => {
538+
ExprKind::ValueUnsafeBinderCast { source, kind } => {
539539
let source_expr = &this.thir[source];
540540
let temp = unpack!(
541541
block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
542542
);
543-
// TODO: stick on a projection elem
544-
block.and(PlaceBuilder::from(temp))
543+
block.and(
544+
PlaceBuilder::from(temp).project(PlaceElem::UnsafeBinderCast(kind, expr.ty)),
545+
)
545546
}
546547

547548
ExprKind::Array { .. }
@@ -734,7 +735,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
734735
| ProjectionElem::OpaqueCast(..)
735736
| ProjectionElem::Subtype(..)
736737
| ProjectionElem::ConstantIndex { .. }
737-
| ProjectionElem::Subslice { .. } => (),
738+
| ProjectionElem::Subslice { .. }
739+
| ProjectionElem::UnsafeBinderCast(..) => (),
738740
}
739741
}
740742
}

compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs

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

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