Skip to content

Commit 2fd3007

Browse files
authored
Rollup merge of #130514 - compiler-errors:unsafe-binders, r=oli-obk
Implement MIR lowering for unsafe binders This is the final bit of the unsafe binders puzzle. It implements MIR, CTFE, and codegen for unsafe binders, and enforces that (for now) they are `Copy`. Later on, I'll introduce a new trait that relaxes this requirement to being "is `Copy` or `ManuallyDrop<T>`" which more closely models how we treat union fields. Namely, wrapping unsafe binders is now `Rvalue::WrapUnsafeBinder`, which acts much like an `Rvalue::Aggregate`. Unwrapping unsafe binders are implemented as a MIR projection `ProjectionElem::UnwrapUnsafeBinder`, which acts much like `ProjectionElem::Field`. Tracking: - #130516
2 parents e08cd3c + 442b9a9 commit 2fd3007

File tree

56 files changed

+589
-102
lines changed

Some content is hidden

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

56 files changed

+589
-102
lines changed

compiler/rustc_ast/src/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,7 @@ impl GenBlockKind {
16571657
}
16581658

16591659
/// Whether we're unwrapping or wrapping an unsafe binder
1660-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1660+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
16611661
#[derive(Encodable, Decodable, HashStable_Generic)]
16621662
pub enum UnsafeBinderCastKind {
16631663
// 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
@@ -3915,7 +3915,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
39153915
ProjectionElem::ConstantIndex { .. }
39163916
| ProjectionElem::Subslice { .. }
39173917
| ProjectionElem::Subtype(_)
3918-
| ProjectionElem::Index(_) => kind,
3918+
| ProjectionElem::Index(_)
3919+
| ProjectionElem::UnwrapUnsafeBinder(_) => kind,
39193920
},
39203921
place_ty.projection_ty(tcx, elem),
39213922
)

compiler/rustc_borrowck/src/diagnostics/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
370370
ProjectionElem::Downcast(..) => (),
371371
ProjectionElem::OpaqueCast(..) => (),
372372
ProjectionElem::Subtype(..) => (),
373+
ProjectionElem::UnwrapUnsafeBinder(_) => (),
373374
ProjectionElem::Field(field, _ty) => {
374375
// FIXME(project-rfc_2229#36): print capture precisely here.
375376
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -450,9 +451,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
450451
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
451452
}
452453
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
453-
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
454-
PlaceTy::from_ty(*ty)
455-
}
454+
ProjectionElem::Subtype(ty)
455+
| ProjectionElem::OpaqueCast(ty)
456+
| ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
456457
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
457458
},
458459
};

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::UnwrapUnsafeBinder(_),
171172
],
172173
} => bug!("Unexpected immutable place."),
173174
}

compiler/rustc_borrowck/src/lib.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
13981398
self.consume_operand(location, (operand, span), state);
13991399
}
14001400
}
1401+
1402+
Rvalue::WrapUnsafeBinder(op, _) => {
1403+
self.consume_operand(location, (op, span), state);
1404+
}
14011405
}
14021406
}
14031407

@@ -1770,7 +1774,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
17701774
// So it's safe to skip these.
17711775
ProjectionElem::OpaqueCast(_)
17721776
| ProjectionElem::Subtype(_)
1773-
| ProjectionElem::Downcast(_, _) => (),
1777+
| ProjectionElem::Downcast(_, _)
1778+
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
17741779
}
17751780

17761781
place_ty = place_ty.projection_ty(tcx, elem);
@@ -2004,6 +2009,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
20042009
// FIXME: is this true even if P is an adt with a dtor?
20052010
{ }
20062011

2012+
ProjectionElem::UnwrapUnsafeBinder(_) => {
2013+
check_parent_of_field(self, location, place_base, span, state);
2014+
}
2015+
20072016
// assigning to (*P) requires P to be initialized
20082017
ProjectionElem::Deref => {
20092018
self.check_if_full_path_is_moved(
@@ -2384,7 +2393,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
23842393
| ProjectionElem::Subslice { .. }
23852394
| ProjectionElem::Subtype(..)
23862395
| ProjectionElem::OpaqueCast { .. }
2387-
| ProjectionElem::Downcast(..) => {
2396+
| ProjectionElem::Downcast(..)
2397+
| ProjectionElem::UnwrapUnsafeBinder(_) => {
23882398
let upvar_field_projection = self.is_upvar_field_projection(place);
23892399
if let Some(field) = upvar_field_projection {
23902400
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::UnwrapUnsafeBinder(_), _, _) => {
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::UnwrapUnsafeBinder(_), _) => {
525+
todo!()
526+
}
522527
}
523528
}

compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs

+4
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
325325
self.consume_operand(location, operand);
326326
}
327327
}
328+
329+
Rvalue::WrapUnsafeBinder(op, _) => {
330+
self.consume_operand(location, op);
331+
}
328332
}
329333
}
330334

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::UnwrapUnsafeBinder(_) => {
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

+44-2
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
302302
)
303303
.unwrap();
304304
}
305+
ProjectionElem::UnwrapUnsafeBinder(ty) => {
306+
let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else {
307+
unreachable!();
308+
};
309+
let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars(
310+
self.body().source_info(location).span,
311+
BoundRegionConversionTime::HigherRankedType,
312+
binder_ty.into(),
313+
);
314+
self.typeck
315+
.relate_types(
316+
ty,
317+
context.ambient_variance(),
318+
found_ty,
319+
location.to_locations(),
320+
ConstraintCategory::Boring,
321+
)
322+
.unwrap();
323+
}
305324
ProjectionElem::Subtype(_) => {
306325
bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
307326
}
@@ -2233,6 +2252,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
22332252
self.check_operand(right, location);
22342253
}
22352254

2255+
Rvalue::WrapUnsafeBinder(op, ty) => {
2256+
self.check_operand(op, location);
2257+
let operand_ty = op.ty(self.body, self.tcx());
2258+
2259+
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
2260+
unreachable!();
2261+
};
2262+
let expected_ty = self.infcx.instantiate_binder_with_fresh_vars(
2263+
self.body().source_info(location).span,
2264+
BoundRegionConversionTime::HigherRankedType,
2265+
binder_ty.into(),
2266+
);
2267+
self.sub_types(
2268+
operand_ty,
2269+
expected_ty,
2270+
location.to_locations(),
2271+
ConstraintCategory::Boring,
2272+
)
2273+
.unwrap();
2274+
}
2275+
22362276
Rvalue::RawPtr(..)
22372277
| Rvalue::ThreadLocalRef(..)
22382278
| Rvalue::Len(..)
@@ -2258,7 +2298,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
22582298
| Rvalue::NullaryOp(..)
22592299
| Rvalue::CopyForDeref(..)
22602300
| Rvalue::UnaryOp(..)
2261-
| Rvalue::Discriminant(..) => None,
2301+
| Rvalue::Discriminant(..)
2302+
| Rvalue::WrapUnsafeBinder(..) => None,
22622303

22632304
Rvalue::Aggregate(aggregate, _) => match **aggregate {
22642305
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
@@ -2450,7 +2491,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
24502491
| ProjectionElem::OpaqueCast(..)
24512492
| ProjectionElem::Index(..)
24522493
| ProjectionElem::ConstantIndex { .. }
2453-
| ProjectionElem::Subslice { .. } => {
2494+
| ProjectionElem::Subslice { .. }
2495+
| ProjectionElem::UnwrapUnsafeBinder(_) => {
24542496
// other field access
24552497
}
24562498
ProjectionElem::Subtype(_) => {

compiler/rustc_codegen_cranelift/src/base.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,10 @@ fn codegen_stmt<'tcx>(
925925
}
926926
crate::discriminant::codegen_set_discriminant(fx, lval, variant_index);
927927
}
928+
Rvalue::WrapUnsafeBinder(ref operand, _to_ty) => {
929+
let operand = codegen_operand(fx, operand);
930+
lval.write_cvalue_transmute(fx, operand);
931+
}
928932
}
929933
}
930934
StatementKind::StorageLive(_)
@@ -993,7 +997,9 @@ pub(crate) fn codegen_place<'tcx>(
993997
cplace = cplace.place_deref(fx);
994998
}
995999
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
996-
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)),
1000+
PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => {
1001+
cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
1002+
}
9971003
PlaceElem::Field(field, _ty) => {
9981004
cplace = cplace.place_field(fx, field);
9991005
}

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::UnwrapUnsafeBinder(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_codegen_ssa/src/mir/rvalue.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
823823

824824
OperandRef { val: OperandValue::Immediate(val), layout: box_layout }
825825
}
826+
mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => {
827+
let operand = self.codegen_operand(bx, operand);
828+
let binder_ty = self.monomorphize(binder_ty);
829+
let layout = bx.cx().layout_of(binder_ty);
830+
OperandRef { val: operand.val, layout }
831+
}
826832
}
827833
}
828834

@@ -1123,7 +1129,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11231129
mir::Rvalue::Discriminant(..) |
11241130
mir::Rvalue::NullaryOp(..) |
11251131
mir::Rvalue::ThreadLocalRef(_) |
1126-
mir::Rvalue::Use(..) => // (*)
1132+
mir::Rvalue::Use(..) |
1133+
mir::Rvalue::WrapUnsafeBinder(..) => // (*)
11271134
true,
11281135
// Arrays are always aggregates, so it's not worth checking anything here.
11291136
// (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)

compiler/rustc_const_eval/src/check_consts/check.rs

+4
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
728728
);
729729
}
730730
}
731+
732+
Rvalue::WrapUnsafeBinder(..) => {
733+
// Unsafe binders are always trivial to create.
734+
}
731735
}
732736
}
733737

compiler/rustc_const_eval/src/check_consts/qualifs.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ where
258258
in_place::<Q, _>(cx, in_local, place.as_ref())
259259
}
260260

261+
Rvalue::WrapUnsafeBinder(op, _) => in_operand::<Q, _>(cx, in_local, op),
262+
261263
Rvalue::Aggregate(kind, operands) => {
262264
// Return early if we know that the struct or enum being constructed is always
263265
// qualified.
@@ -297,7 +299,8 @@ where
297299
| ProjectionElem::ConstantIndex { .. }
298300
| ProjectionElem::Subslice { .. }
299301
| ProjectionElem::Downcast(_, _)
300-
| ProjectionElem::Index(_) => {}
302+
| ProjectionElem::Index(_)
303+
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
301304
}
302305

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

compiler/rustc_const_eval/src/check_consts/resolver.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ where
202202
| mir::Rvalue::NullaryOp(..)
203203
| mir::Rvalue::UnaryOp(..)
204204
| mir::Rvalue::Discriminant(..)
205-
| mir::Rvalue::Aggregate(..) => {}
205+
| mir::Rvalue::Aggregate(..)
206+
| mir::Rvalue::WrapUnsafeBinder(..) => {}
206207
}
207208
}
208209

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+
UnwrapUnsafeBinder(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_const_eval/src/interpret/step.rs

+7
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
277277
let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
278278
self.write_immediate(*discr, &dest)?;
279279
}
280+
281+
WrapUnsafeBinder(ref op, _ty) => {
282+
// Constructing an unsafe binder acts like a transmute
283+
// since the operand's layout does not change.
284+
let op = self.eval_operand(op, None)?;
285+
self.copy_op_allow_transmute(&op, &dest)?;
286+
}
280287
}
281288

282289
trace!("{:?}", self.dump_place(&dest));

compiler/rustc_hir_typeck/src/expr.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1658,8 +1658,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16581658
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
16591659
expected: Expectation<'tcx>,
16601660
) -> Ty<'tcx> {
1661-
self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
1662-
16631661
match kind {
16641662
hir::UnsafeBinderCastKind::Wrap => {
16651663
let ascribed_ty =

compiler/rustc_middle/src/mir/pretty.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
12481248
ShallowInitBox(ref place, ref ty) => {
12491249
with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
12501250
}
1251+
1252+
WrapUnsafeBinder(ref op, ty) => {
1253+
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
1254+
}
12511255
}
12521256
}
12531257
}
@@ -1308,6 +1312,9 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
13081312
ProjectionElem::Index(_)
13091313
| ProjectionElem::ConstantIndex { .. }
13101314
| ProjectionElem::Subslice { .. } => {}
1315+
ProjectionElem::UnwrapUnsafeBinder(_) => {
1316+
write!(fmt, "unwrap_binder!(")?;
1317+
}
13111318
}
13121319
}
13131320

@@ -1356,6 +1363,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
13561363
ProjectionElem::Subslice { from, to, from_end: false } => {
13571364
write!(fmt, "[{from:?}..{to:?}]")?;
13581365
}
1366+
ProjectionElem::UnwrapUnsafeBinder(ty) => {
1367+
write!(fmt, "; {ty})")?;
1368+
}
13591369
}
13601370
}
13611371

0 commit comments

Comments
 (0)