Skip to content

Commit

Permalink
Auto merge of rust-lang#136185 - matthiaskrgr:rollup-zqzy6wb, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#133151 (Trim extra whitespace in fn ptr suggestion span)
 - rust-lang#133829 (Implement `AtomicT::update` & `AtomicT::try_update`)
 - rust-lang#135367 (Enable `unreachable_pub` lint in `alloc`)
 - rust-lang#135748 (Lower index bounds checking to `PtrMetadata`, this time with the right fake borrow semantics 😸)
 - rust-lang#135805 (Add missing allocator safety in alloc crate)
 - rust-lang#135886 (Document purpose of closure in from_fn.rs more clearly)
 - rust-lang#135961 (Fix 2/4 tests skipped by opt-dist)
 - rust-lang#136012 (Document powf and powi values that are always 1.0)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jan 28, 2025
2 parents aa6f5ab + 9a192b2 commit fdd1a3b
Show file tree
Hide file tree
Showing 155 changed files with 2,374 additions and 1,993 deletions.
11 changes: 7 additions & 4 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,15 +1284,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
);
}

&Rvalue::RawPtr(mutability, place) => {
let access_kind = match mutability {
Mutability::Mut => (
&Rvalue::RawPtr(kind, place) => {
let access_kind = match kind {
RawPtrKind::Mut => (
Deep,
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
kind: MutBorrowKind::Default,
})),
),
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
RawPtrKind::FakeForPtrMetadata => {
(Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
}
};

self.access_place(
Expand Down
21 changes: 10 additions & 11 deletions compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ use std::ops::ControlFlow;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::bug;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{
self, BasicBlock, Body, BorrowKind, FakeBorrowKind, InlineAsmOperand, Location, Mutability,
NonDivergingIntrinsic, Operand, Place, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind,
};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use tracing::debug;

Expand Down Expand Up @@ -60,7 +56,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
self.consume_operand(location, op);
}
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
src,
dst,
count,
Expand Down Expand Up @@ -273,15 +269,18 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
}

&Rvalue::RawPtr(mutability, place) => {
let access_kind = match mutability {
Mutability::Mut => (
&Rvalue::RawPtr(kind, place) => {
let access_kind = match kind {
RawPtrKind::Mut => (
Deep,
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
kind: mir::MutBorrowKind::Default,
kind: MutBorrowKind::Default,
})),
),
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
RawPtrKind::FakeForPtrMetadata => {
(Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
}
};

self.access_place(location, place, access_kind, LocalMutationIsAllowed::No);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
let tcx = self.tcx();
let maybe_uneval = match constant.const_ {
Const::Ty(_, ct) => match ct.kind() {
ty::ConstKind::Unevaluated(_) => {
bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
ty::ConstKind::Unevaluated(uv) => {
Some(UnevaluatedConst { def: uv.def, args: uv.args, promoted: None })
}
_ => None,
},
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::Rvalue::CopyForDeref(place) => {
self.codegen_operand(bx, &mir::Operand::Copy(place))
}
mir::Rvalue::RawPtr(mutability, place) => {
let mk_ptr =
move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability);
mir::Rvalue::RawPtr(kind, place) => {
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
Ty::new_ptr(tcx, ty, kind.to_mutbl_lossy())
};
self.codegen_place_to_pointer(bx, place, mk_ptr)
}

Expand Down
31 changes: 24 additions & 7 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}

Rvalue::Ref(_, BorrowKind::Mut { .. }, place)
| Rvalue::RawPtr(Mutability::Mut, place) => {
| Rvalue::RawPtr(RawPtrKind::Mut, place) => {
// Inside mutable statics, we allow arbitrary mutable references.
// We've allowed `static mut FOO = &mut [elements];` for a long time (the exact
// reasons why are lost to history), and there is no reason to restrict that to
Expand All @@ -536,7 +536,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}

Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
| Rvalue::RawPtr(Mutability::Not, place) => {
| Rvalue::RawPtr(RawPtrKind::Const, place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
self.ccx,
&mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
Expand All @@ -548,6 +548,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}

Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => {
// These are only inserted for slice length, so the place must already be indirect.
// This implies we do not have to worry about whether the borrow escapes.
assert!(place.is_indirect(), "fake borrows are always indirect");
}

Rvalue::Cast(
CastKind::PointerCoercion(
PointerCoercion::MutToConstPointer
Expand Down Expand Up @@ -586,12 +592,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
) => {}
Rvalue::ShallowInitBox(_, _) => {}

Rvalue::UnaryOp(_, operand) => {
Rvalue::UnaryOp(op, operand) => {
let ty = operand.ty(self.body, self.tcx);
if is_int_bool_float_or_char(ty) {
// Int, bool, float, and char operations are fine.
} else {
span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
match op {
UnOp::Not | UnOp::Neg => {
if is_int_bool_float_or_char(ty) {
// Int, bool, float, and char operations are fine.
} else {
span_bug!(
self.span,
"non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}",
);
}
}
UnOp::PtrMetadata => {
// Getting the metadata from a pointer is always const.
// We already validated the type is valid in the validator.
}
}
}

Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_const_eval/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_immediate(*val, &dest)?;
}

RawPtr(_, place) => {
RawPtr(kind, place) => {
// Figure out whether this is an addr_of of an already raw place.
let place_base_raw = if place.is_indirect_first_projection() {
let ty = self.frame().body.local_decls[place.local].ty;
Expand All @@ -250,8 +250,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let src = self.eval_place(place)?;
let place = self.force_allocation(&src)?;
let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
if !place_base_raw {
// If this was not already raw, it needs retagging.
if !place_base_raw && !kind.is_fake() {
// If this was not already raw, it needs retagging -- except for "fake"
// raw borrows whose defining property is that they do not get retagged.
val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
}
self.write_immediate(*val, &dest)?;
Expand Down
55 changes: 54 additions & 1 deletion compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,59 @@ pub enum BorrowKind {
Mut { kind: MutBorrowKind },
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable)]
pub enum RawPtrKind {
Mut,
Const,
/// Creates a raw pointer to a place that will only be used to access its metadata,
/// not the data behind the pointer. Note that this limitation is *not* enforced
/// by the validator.
///
/// The borrow checker allows overlap of these raw pointers with references to the
/// data. This is sound even if the pointer is "misused" since any such use is anyway
/// unsafe. In terms of the operational semantics (i.e., Miri), this is equivalent
/// to `RawPtrKind::Mut`, but will never incur a retag.
FakeForPtrMetadata,
}

impl From<Mutability> for RawPtrKind {
fn from(other: Mutability) -> Self {
match other {
Mutability::Mut => RawPtrKind::Mut,
Mutability::Not => RawPtrKind::Const,
}
}
}

impl RawPtrKind {
pub fn is_fake(self) -> bool {
match self {
RawPtrKind::Mut | RawPtrKind::Const => false,
RawPtrKind::FakeForPtrMetadata => true,
}
}

pub fn to_mutbl_lossy(self) -> Mutability {
match self {
RawPtrKind::Mut => Mutability::Mut,
RawPtrKind::Const => Mutability::Not,

// We have no type corresponding to a fake borrow, so use
// `*const` as an approximation.
RawPtrKind::FakeForPtrMetadata => Mutability::Not,
}
}

pub fn ptr_str(self) -> &'static str {
match self {
RawPtrKind::Mut => "mut",
RawPtrKind::Const => "const",
RawPtrKind::FakeForPtrMetadata => "const (fake)",
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable)]
pub enum MutBorrowKind {
Expand Down Expand Up @@ -1356,7 +1409,7 @@ pub enum Rvalue<'tcx> {
///
/// Like with references, the semantics of this operation are heavily dependent on the aliasing
/// model.
RawPtr(Mutability, Place<'tcx>),
RawPtr(RawPtrKind, Place<'tcx>),

/// Yields the length of the place, as a `usize`.
///
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ impl<'tcx> Rvalue<'tcx> {
let place_ty = place.ty(local_decls, tcx).ty;
Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
}
Rvalue::RawPtr(mutability, ref place) => {
Rvalue::RawPtr(kind, ref place) => {
let place_ty = place.ty(local_decls, tcx).ty;
Ty::new_ptr(tcx, place_ty, mutability)
Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy())
}
Rvalue::Len(..) => tcx.types.usize,
Rvalue::Cast(.., ty) => ty,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/type_foldable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ TrivialTypeTraversalImpls! {
SourceScopeLocalData,
UserTypeAnnotationIndex,
BorrowKind,
RawPtrKind,
CastKind,
BasicBlock,
SwitchTargets,
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -685,12 +685,15 @@ macro_rules! make_mir_visitor {

Rvalue::RawPtr(m, path) => {
let ctx = match m {
Mutability::Mut => PlaceContext::MutatingUse(
RawPtrKind::Mut => PlaceContext::MutatingUse(
MutatingUseContext::RawBorrow
),
Mutability::Not => PlaceContext::NonMutatingUse(
RawPtrKind::Const => PlaceContext::NonMutatingUse(
NonMutatingUseContext::RawBorrow
),
RawPtrKind::FakeForPtrMetadata => PlaceContext::NonMutatingUse(
NonMutatingUseContext::Inspect
),
};
self.visit_place(path, ctx, location);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)?)))
Expand Down
79 changes: 71 additions & 8 deletions compiler/rustc_mir_build/src/builder/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
}
Expand Down
Loading

0 comments on commit fdd1a3b

Please sign in to comment.