Skip to content

Commit cd7f471

Browse files
committed
Add docs, remove code, change subtyper code
1 parent 3148e6a commit cd7f471

24 files changed

+106
-363
lines changed

compiler/rustc_borrowck/src/diagnostics/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -318,13 +318,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
318318
PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
319319
ProjectionElem::Deref
320320
| ProjectionElem::Index(..)
321-
| ProjectionElem::Subtype(..)
322321
| ProjectionElem::ConstantIndex { .. }
323322
| ProjectionElem::Subslice { .. } => {
324323
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
325324
}
326325
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
327-
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
326+
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
327+
PlaceTy::from_ty(*ty)
328+
}
328329
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
329330
},
330331
};

compiler/rustc_borrowck/src/places_conflict.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,13 @@ fn place_components_conflict<'tcx>(
243243
}
244244

245245
(ProjectionElem::Deref, _, Deep)
246-
| (ProjectionElem::Subtype(_), _, _)
247246
| (ProjectionElem::Deref, _, AccessDepth::Drop)
248247
| (ProjectionElem::Field { .. }, _, _)
249248
| (ProjectionElem::Index { .. }, _, _)
250249
| (ProjectionElem::ConstantIndex { .. }, _, _)
251250
| (ProjectionElem::Subslice { .. }, _, _)
252251
| (ProjectionElem::OpaqueCast { .. }, _, _)
252+
| (ProjectionElem::Subtype(_), _, _)
253253
| (ProjectionElem::Downcast { .. }, _, _) => {
254254
// Recursive case. This can still be disjoint on a
255255
// further iteration if this a shallow access and
@@ -360,7 +360,6 @@ fn place_projection_conflict<'tcx>(
360360
(
361361
ProjectionElem::Index(..),
362362
ProjectionElem::Index(..)
363-
| ProjectionElem::Subtype(..)
364363
| ProjectionElem::ConstantIndex { .. }
365364
| ProjectionElem::Subslice { .. },
366365
)
@@ -505,12 +504,12 @@ fn place_projection_conflict<'tcx>(
505504
debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
506505
Overlap::EqualOrDisjoint
507506
}
508-
(ProjectionElem::Subtype(_), _) => Overlap::EqualOrDisjoint,
509507
(
510508
ProjectionElem::Deref
511509
| ProjectionElem::Field(..)
512510
| ProjectionElem::Index(..)
513511
| ProjectionElem::ConstantIndex { .. }
512+
| ProjectionElem::Subtype(_)
514513
| ProjectionElem::OpaqueCast { .. }
515514
| ProjectionElem::Subslice { .. }
516515
| ProjectionElem::Downcast(..),

compiler/rustc_borrowck/src/prefixes.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
8989
cursor = cursor_base;
9090
continue 'cursor;
9191
}
92-
ProjectionElem::Subtype(..) => continue 'cursor,
92+
ProjectionElem::Subtype(..) => {
93+
panic!("Subtype projection is not allowed before borrow check")
94+
}
9395
ProjectionElem::Deref => {
9496
// (handled below)
9597
}

compiler/rustc_borrowck/src/type_check/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
621621
span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
622622
}))
623623
}
624-
ProjectionElem::Subtype(ty) => PlaceTy::from_ty(ty),
625624
ProjectionElem::Index(i) => {
626625
let index_ty = Place::from(i).ty(self.body(), tcx).ty;
627626
if index_ty != tcx.types.usize {
@@ -717,6 +716,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
717716
}
718717
PlaceTy::from_ty(fty)
719718
}
719+
ProjectionElem::Subtype(_) => {
720+
let guard = span_mirbug_and_err!(
721+
self,
722+
place,
723+
"ProjectionElem::Subtype shouldn't exist in borrowck"
724+
);
725+
PlaceTy::from_ty(Ty::new_error(tcx, guard))
726+
}
720727
ProjectionElem::OpaqueCast(ty) => {
721728
let ty = self.sanitize_type(place, ty);
722729
let ty = self.cx.normalize(ty, location);

compiler/rustc_codegen_cranelift/src/base.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -872,13 +872,11 @@ pub(crate) fn codegen_place<'tcx>(
872872

873873
for elem in place.projection {
874874
match elem {
875-
PlaceElem::Subtype(_) => {
876-
continue;
877-
}
878875
PlaceElem::Deref => {
879876
cplace = cplace.place_deref(fx);
880877
}
881878
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
879+
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, ty),
882880
PlaceElem::Field(field, _ty) => {
883881
cplace = cplace.place_field(fx, field);
884882
}

compiler/rustc_codegen_cranelift/src/value_and_place.rs

+8
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,14 @@ impl<'tcx> CPlace<'tcx> {
674674
}
675675
}
676676

677+
pub(crate) fn place_transmute_type(
678+
self,
679+
fx: &mut FunctionCx<'_, '_, 'tcx>,
680+
ty: Ty<'tcx>,
681+
) -> CPlace<'tcx> {
682+
CPlace { inner: self.inner, layout: fx.layout_of(fx.monomorphize(ty)) }
683+
}
684+
677685
pub(crate) fn place_field(
678686
self,
679687
fx: &mut FunctionCx<'_, '_, 'tcx>,

compiler/rustc_codegen_ssa/src/mir/place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
466466
mir::ProjectionElem::OpaqueCast(ty) => {
467467
bug!("encountered OpaqueCast({ty}) in codegen")
468468
}
469+
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
469470
mir::ProjectionElem::Index(index) => {
470471
let index = &mir::Operand::Copy(mir::Place::from(index));
471472
let index = self.codegen_operand(bx, index);
@@ -499,7 +500,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
499500
subslice
500501
}
501502
mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
502-
mir::ProjectionElem::Subtype(_) => continue,
503503
};
504504
}
505505
debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);

compiler/rustc_const_eval/src/interpret/operand.rs

-3
Original file line numberDiff line numberDiff line change
@@ -665,9 +665,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
665665
let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?;
666666
// Using `try_fold` turned out to be bad for performance, hence the loop.
667667
for elem in mir_place.projection.iter() {
668-
if elem.is_subtype() {
669-
continue;
670-
}
671668
op = self.project(&op, elem)?
672669
}
673670

compiler/rustc_const_eval/src/interpret/projection.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ where
319319
OpaqueCast(ty) => {
320320
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
321321
}
322+
// We don't want anything happening here, this is here as a dummy.
323+
Subtype(_) => base.transmute(base.layout(), self)?,
322324
Field(field, _) => self.project_field(base, field.index())?,
323325
Downcast(_, variant) => self.project_downcast(base, variant)?,
324326
Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
@@ -332,7 +334,6 @@ where
332334
self.project_constant_index(base, offset, min_length, from_end)?
333335
}
334336
Subslice { from, to, from_end } => self.project_subslice(base, from, to, from_end)?,
335-
Subtype(ty) => base.transmute(self.layout_of(ty)?, self)?,
336337
})
337338
}
338339
}

compiler/rustc_const_eval/src/transform/validate.rs

+19-24
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use rustc_target::spec::abi::Abi;
1616

1717
use crate::util::is_within_packed;
1818

19+
use crate::util::is_subtype;
20+
1921
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2022
enum EdgeKind {
2123
Unwind,
@@ -602,35 +604,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
602604
return true;
603605
}
604606

605-
crate::util::is_subtype(self.tcx, self.param_env, src, dest)
607+
return crate::util::is_subtype(self.tcx, self.param_env, src, dest);
606608
}
607609
}
608610

609611
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
610612
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
611-
match operand {
612-
Operand::Copy(place) | Operand::Move(place) => {
613-
if let Some(stmt) = self.body.stmt_at(location).left() {
614-
match &stmt.kind {
615-
StatementKind::Assign(box (lval, rvalue)) => {
616-
let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
617-
let lval_ty = lval.ty(&self.body.local_decls, self.tcx).ty;
618-
619-
if !place.is_subtype()
620-
&& place_ty != lval_ty
621-
&& rvalue.ty(&self.body.local_decls, self.tcx) != lval_ty
622-
&& (rvalue.ty(&self.body.local_decls, self.tcx).is_closure()
623-
!= lval_ty.is_closure())
624-
{
625-
self.fail(location, format!("Subtyping is not allowed between types {place_ty:#?} and {lval_ty:#?}"))
626-
}
627-
}
628-
_ => (),
629-
}
630-
}
631-
}
632-
_ => (),
633-
}
634613
// This check is somewhat expensive, so only run it when -Zvalidate-mir is passed.
635614
if self.tcx.sess.opts.unstable_opts.validate_mir
636615
&& self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
@@ -776,6 +755,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
776755
}
777756
}
778757
}
758+
ProjectionElem::Subtype(ty) => {
759+
if !is_subtype(
760+
self.tcx,
761+
self.param_env,
762+
ty,
763+
place_ref.ty(&self.body.local_decls, self.tcx).ty,
764+
) {
765+
self.fail(
766+
location,
767+
format!(
768+
"Failed subtyping {ty:#?} and {:#?}",
769+
place_ref.ty(&self.body.local_decls, self.tcx).ty
770+
),
771+
)
772+
}
773+
}
779774
_ => {}
780775
}
781776
self.super_projection_elem(place_ref, elem, context, location);

compiler/rustc_middle/src/mir/pretty.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
11031103
for &elem in projection.iter().rev() {
11041104
match elem {
11051105
ProjectionElem::OpaqueCast(_)
1106+
| ProjectionElem::Subtype(_)
11061107
| ProjectionElem::Downcast(_, _)
11071108
| ProjectionElem::Field(_, _) => {
11081109
write!(fmt, "(").unwrap();
@@ -1125,6 +1126,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
11251126
ProjectionElem::OpaqueCast(ty) => {
11261127
write!(fmt, " as {ty})")?;
11271128
}
1129+
ProjectionElem::Subtype(ty) => {
1130+
write!(fmt, "as {ty})")?;
1131+
}
11281132
ProjectionElem::Downcast(Some(name), _index) => {
11291133
write!(fmt, " as {name})")?;
11301134
}

compiler/rustc_middle/src/mir/statement.rs

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl<V, T> ProjectionElem<V, T> {
5757
Self::Field(_, _)
5858
| Self::Index(_)
5959
| Self::OpaqueCast(_)
60+
| Self::Subtype(_)
6061
| Self::ConstantIndex { .. }
6162
| Self::Subslice { .. }
6263
| Self::Downcast(_, _) => false,
@@ -70,6 +71,7 @@ impl<V, T> ProjectionElem<V, T> {
7071
Self::Deref | Self::Index(_) => false,
7172
Self::Field(_, _)
7273
| Self::OpaqueCast(_)
74+
| Self::Subtype(_)
7375
| Self::ConstantIndex { .. }
7476
| Self::Subslice { .. }
7577
| Self::Downcast(_, _) => true,
@@ -95,6 +97,7 @@ impl<V, T> ProjectionElem<V, T> {
9597
| Self::Field(_, _) => true,
9698
Self::ConstantIndex { from_end: true, .. }
9799
| Self::Index(_)
100+
| Self::Subtype(_)
98101
| Self::OpaqueCast(_)
99102
| Self::Subslice { .. } => false,
100103
}

compiler/rustc_middle/src/mir/syntax.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,13 @@ pub enum ProjectionElem<V, T> {
10761076
/// requiring an intermediate variable.
10771077
OpaqueCast(T),
10781078

1079+
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
1080+
/// type of lvalue doesn't match type of rvalue, primary goal being making subtyping
1081+
/// explicit during optimizations and codegen.
1082+
///
1083+
/// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
1084+
/// borrowchecker, as we only care about subtyping that can affect trait selection and
1085+
/// `TypeId`.
10791086
Subtype(T),
10801087
}
10811088

compiler/rustc_middle/src/mir/visit.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1109,8 +1109,12 @@ macro_rules! visit_place_fns {
11091109
self.visit_ty(&mut new_ty, TyContext::Location(location));
11101110
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
11111111
}
1112+
PlaceElem::Subtype(ty) => {
1113+
let mut new_ty = ty;
1114+
self.visit_ty(&mut new_ty, TyContext::Location(location));
1115+
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
1116+
}
11121117
PlaceElem::Deref
1113-
| PlaceElem::Subtype { .. }
11141118
| PlaceElem::ConstantIndex { .. }
11151119
| PlaceElem::Subslice { .. }
11161120
| PlaceElem::Downcast(..) => None,

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
112112
let mut union_path = None;
113113

114114
for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
115-
if elem.is_subtype() {
116-
continue;
117-
}
115+
// We don't care creating `MovePath` for `ProjectionElem::Subtype(T)` because it's for debugging/validating
116+
// purposes it's movement doesn't affect anything.
118117
let body = self.builder.body;
119118
let tcx = self.builder.tcx;
120119
let place_ty = place_ref.ty(body, tcx).ty;
@@ -233,7 +232,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
233232
// `OpaqueCast` only transmutes the type, so no moves there and
234233
// `Downcast` only changes information about a `Place` without moving
235234
// So it's safe to skip these.
236-
ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (),
235+
ProjectionElem::OpaqueCast(_)
236+
| ProjectionElem::Subtype(_)
237+
| ProjectionElem::Downcast(_, _) => (),
237238
}
238239
if union_path.is_none() {
239240
// inlined from add_move_path because of a borrowck conflict with the iterator

compiler/rustc_mir_transform/src/add_subtyping_projections.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ use rustc_middle::ty::TyCtxt;
77

88
pub struct Subtyper;
99

10-
pub struct SubTypeCheker<'a, 'tcx> {
10+
pub struct SubTypeChecker<'a, 'tcx> {
1111
tcx: TyCtxt<'tcx>,
1212
patcher: MirPatch<'tcx>,
1313
local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
1414
}
1515

16-
impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
16+
impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
1717
fn tcx(&self) -> TyCtxt<'tcx> {
1818
self.tcx
1919
}
@@ -25,28 +25,30 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> {
2525
location: Location,
2626
) {
2727
let place_ty = place.ty(self.local_decls, self.tcx);
28-
let rval_ty = rvalue.ty(self.local_decls, self.tcx);
28+
let mut rval_ty = rvalue.ty(self.local_decls, self.tcx);
2929
if place_ty.ty != rval_ty {
30+
// Not erasing this causes `Free Regions` errors in validator,
31+
// when rval is `ReStatic`.
32+
rval_ty = self.tcx.erase_regions_ty(rval_ty);
3033
let temp = self
3134
.patcher
3235
.new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
33-
let new_place =
34-
Place::from(temp).project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
36+
let new_place = Place::from(temp);
3537
self.patcher.add_assign(location, new_place, rvalue.clone());
36-
let new_rval = Rvalue::Use(Operand::Move(new_place));
37-
*rvalue = new_rval;
38+
let subtyped =
39+
new_place.project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx);
40+
*rvalue = Rvalue::Use(Operand::Move(subtyped));
3841
}
3942
}
4043
}
4144

4245
pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
4346
let patch = MirPatch::new(body);
44-
let mut checker = SubTypeCheker { tcx, patcher: patch, local_decls: &body.local_decls };
47+
let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls };
4548

4649
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
4750
checker.visit_basic_block_data(bb, data);
4851
}
49-
5052
checker.patcher.apply(body);
5153
}
5254

compiler/rustc_mir_transform/src/gvn.rs

+1
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
306306
}
307307
ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index),
308308
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
309+
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
309310
};
310311
value = self.insert(Value::Projection(value, proj));
311312
}

tabula.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-pass
2+
#![deny(drop_bounds)]
3+
// As a special exemption, `impl Drop` in the return position raises no error.
4+
// This allows a convenient way to return an unnamed drop guard.
5+
fn voldemort_type() -> impl Drop {
6+
struct Voldemort;
7+
impl Drop for Voldemort {
8+
fn drop(&mut self) {}
9+
}
10+
Voldemort
11+
}
12+
fn main() {
13+
let _ = voldemort_type();
14+
}

0 commit comments

Comments
 (0)