Skip to content

Commit b777368

Browse files
committed
document unstated condition of Subslice and validate more
1 parent de3cc71 commit b777368

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ pub enum RuntimePhase {
136136
/// * [`StatementKind::Retag`]
137137
/// * [`StatementKind::SetDiscriminant`]
138138
/// * [`StatementKind::Deinit`]
139+
/// * [`PlaceElem::ConstantIndex`] / [`PlaceElem::Subslice`] after [`PlaceElem::Subslice`]
139140
///
140141
/// Furthermore, `Copy` operands are allowed for non-`Copy` types.
141142
Initial = 0,
@@ -1250,6 +1251,9 @@ pub enum ProjectionElem<V, T> {
12501251
///
12511252
/// If `from_end` is true `slice[from..slice.len() - to]`.
12521253
/// Otherwise `array[from..to]`.
1254+
///
1255+
/// This projection cannot have `ConstantIndex` or additional `Subslice` projections after it
1256+
/// before runtime MIR.
12531257
Subslice {
12541258
from: u64,
12551259
to: u64,

compiler/rustc_mir_transform/src/validate.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,11 +801,69 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
801801
}
802802
}
803803
ProjectionElem::Index(index) => {
804+
let indexed_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
805+
match indexed_ty.kind() {
806+
ty::Array(_, _) | ty::Slice(_) => {}
807+
_ => self.fail(location, format!("{indexed_ty:?} cannot be indexed")),
808+
}
809+
804810
let index_ty = self.body.local_decls[index].ty;
805811
if index_ty != self.tcx.types.usize {
806812
self.fail(location, format!("bad index ({index_ty} != usize)"))
807813
}
808814
}
815+
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
816+
let indexed_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
817+
match indexed_ty.kind() {
818+
ty::Array(_, _) => {
819+
if from_end {
820+
self.fail(location, "arrays should not be indexed from end");
821+
}
822+
}
823+
ty::Slice(_) => {}
824+
_ => self.fail(location, format!("{indexed_ty:?} cannot be indexed")),
825+
}
826+
827+
if from_end {
828+
if offset > min_length {
829+
self.fail(
830+
location,
831+
format!(
832+
"constant index with offset -{offset} out of bounds of min length {min_length}"
833+
),
834+
);
835+
}
836+
} else {
837+
if offset >= min_length {
838+
self.fail(
839+
location,
840+
format!(
841+
"constant index with offset {offset} out of bounds of min length {min_length}"
842+
),
843+
);
844+
}
845+
}
846+
}
847+
ProjectionElem::Subslice { from, to, from_end } => {
848+
let indexed_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
849+
match indexed_ty.kind() {
850+
ty::Array(_, _) => {
851+
if from_end {
852+
self.fail(location, "arrays should not be subsliced from end");
853+
}
854+
}
855+
ty::Slice(_) => {
856+
if !from_end {
857+
self.fail(location, "slices should be subsliced from end");
858+
}
859+
}
860+
_ => self.fail(location, format!("{indexed_ty:?} cannot be indexed")),
861+
}
862+
863+
if !from_end && from > to {
864+
self.fail(location, "backwards subslice {from}..{to}");
865+
}
866+
}
809867
ProjectionElem::OpaqueCast(ty)
810868
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) =>
811869
{
@@ -906,6 +964,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
906964
}
907965
}
908966

967+
if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial)
968+
&& let Some(i) = place
969+
.projection
970+
.iter()
971+
.position(|elem| matches!(elem, ProjectionElem::Subslice { .. }))
972+
&& let Some(tail) = place.projection.get(i + 1..)
973+
&& tail.iter().any(|elem| {
974+
matches!(
975+
elem,
976+
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }
977+
)
978+
})
979+
{
980+
self.fail(
981+
location,
982+
format!("place {place:?} has `ConstantIndex` or `Subslice` after `Subslice`"),
983+
);
984+
}
985+
909986
self.super_place(place, cntxt, location);
910987
}
911988

0 commit comments

Comments
 (0)