Rollup merge of #135748 - compiler-errors:len-2, r=RalfJung,oli-obk
Lower index bounds checking to `PtrMetadata`, this time with the right fake borrow semantics 😸
Change `Rvalue::RawRef` to take a `RawRefKind` instead of just a `Mutability`. Then introduce `RawRefKind::FakeForPtrMetadata` and use that for lowering index bounds checking to a `PtrMetadata`. This new `RawRefKind::FakeForPtrMetadata` acts like a shallow fake borrow in borrowck, which mimics the semantics of the old `Rvalue::Len` operation we're replacing.
We can then use this `RawRefKind` instead of using a span desugaring hack in CTFE.
cc ``@scottmcm`` ``@RalfJung``
This commit is contained in:
commit
21ddd7ab89
117 changed files with 1591 additions and 1704 deletions
|
@ -253,7 +253,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
|
||||
),
|
||||
ExprKind::RawBorrow { mutability, arg } => Ok(
|
||||
Rvalue::RawPtr(*mutability, self.parse_place(*arg)?)
|
||||
Rvalue::RawPtr((*mutability).into(), self.parse_place(*arg)?)
|
||||
),
|
||||
ExprKind::Binary { op, lhs, rhs } => Ok(
|
||||
Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
|
||||
|
|
|
@ -630,6 +630,69 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
block.and(base_place.index(idx))
|
||||
}
|
||||
|
||||
/// Given a place that's either an array or a slice, returns an operand
|
||||
/// with the length of the array/slice.
|
||||
///
|
||||
/// For arrays it'll be `Operand::Constant` with the actual length;
|
||||
/// For slices it'll be `Operand::Move` of a local using `PtrMetadata`.
|
||||
fn len_of_slice_or_array(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
source_info: SourceInfo,
|
||||
) -> Operand<'tcx> {
|
||||
let place_ty = place.ty(&self.local_decls, self.tcx).ty;
|
||||
match place_ty.kind() {
|
||||
ty::Array(_elem_ty, len_const) => {
|
||||
// We know how long an array is, so just use that as a constant
|
||||
// directly -- no locals needed. We do need one statement so
|
||||
// that borrow- and initialization-checking consider it used,
|
||||
// though. FIXME: Do we really *need* to count this as a use?
|
||||
// Could partial array tracking work off something else instead?
|
||||
self.cfg.push_fake_read(block, source_info, FakeReadCause::ForIndex, place);
|
||||
let const_ = Const::Ty(self.tcx.types.usize, *len_const);
|
||||
Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ }))
|
||||
}
|
||||
ty::Slice(_elem_ty) => {
|
||||
let ptr_or_ref = if let [PlaceElem::Deref] = place.projection[..]
|
||||
&& let local_ty = self.local_decls[place.local].ty
|
||||
&& local_ty.is_trivially_pure_clone_copy()
|
||||
{
|
||||
// It's extremely common that we have something that can be
|
||||
// directly passed to `PtrMetadata`, so avoid an unnecessary
|
||||
// temporary and statement in those cases. Note that we can
|
||||
// only do that for `Copy` types -- not `&mut [_]` -- because
|
||||
// the MIR we're building here needs to pass NLL later.
|
||||
Operand::Copy(Place::from(place.local))
|
||||
} else {
|
||||
let ptr_ty = Ty::new_imm_ptr(self.tcx, place_ty);
|
||||
let slice_ptr = self.temp(ptr_ty, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
slice_ptr,
|
||||
Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place),
|
||||
);
|
||||
Operand::Move(slice_ptr)
|
||||
};
|
||||
|
||||
let len = self.temp(self.tcx.types.usize, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
len,
|
||||
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr_or_ref),
|
||||
);
|
||||
|
||||
Operand::Move(len)
|
||||
}
|
||||
_ => {
|
||||
span_bug!(span, "len called on place of type {place_ty:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds_check(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
|
@ -638,25 +701,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
expr_span: Span,
|
||||
source_info: SourceInfo,
|
||||
) -> BasicBlock {
|
||||
let usize_ty = self.tcx.types.usize;
|
||||
let bool_ty = self.tcx.types.bool;
|
||||
// bounds check:
|
||||
let len = self.temp(usize_ty, expr_span);
|
||||
let lt = self.temp(bool_ty, expr_span);
|
||||
let slice = slice.to_place(self);
|
||||
|
||||
// len = len(slice)
|
||||
self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self)));
|
||||
let len = self.len_of_slice_or_array(block, slice, expr_span, source_info);
|
||||
|
||||
// lt = idx < len
|
||||
let bool_ty = self.tcx.types.bool;
|
||||
let lt = self.temp(bool_ty, expr_span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
lt,
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Lt,
|
||||
Box::new((Operand::Copy(Place::from(index)), Operand::Copy(len))),
|
||||
Box::new((Operand::Copy(Place::from(index)), len.to_copy())),
|
||||
),
|
||||
);
|
||||
let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
|
||||
let msg = BoundsCheck { len, index: Operand::Copy(Place::from(index)) };
|
||||
|
||||
// assert!(lt, "...")
|
||||
self.assert(block, Operand::Move(lt), true, msg, expr_span)
|
||||
}
|
||||
|
|
|
@ -303,7 +303,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
hir::Mutability::Not => this.as_read_only_place(block, arg),
|
||||
hir::Mutability::Mut => this.as_place(block, arg),
|
||||
};
|
||||
let address_of = Rvalue::RawPtr(mutability, unpack!(block = place));
|
||||
let address_of = Rvalue::RawPtr(mutability.into(), unpack!(block = place));
|
||||
this.cfg.push_assign(block, source_info, destination, address_of);
|
||||
block.unit()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue