diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 4a2b2942008b8..d9d31ab2c89a1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2147,6 +2147,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + CastKind::PointerAddress => { + let ty_from = op.ty(body, tcx); + let cast_ty_from = CastTy::from_ty(ty_from); + let cast_ty_to = CastTy::from_ty(*ty); + match (cast_ty_from, cast_ty_to) { + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (), + _ => { + span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty) + } + } + } + CastKind::Misc => { let ty_from = op.ty(body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); @@ -2155,7 +2167,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { (None, _) | (_, None | Some(CastTy::FnPtr)) | (Some(CastTy::Float), Some(CastTy::Ptr(_))) - | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => { + | ( + Some(CastTy::Ptr(_) | CastTy::FnPtr), + Some(CastTy::Float | CastTy::Int(_)), + ) => { span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,) } ( @@ -2163,8 +2178,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)), ) | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float)) - | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_))) - | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (), + | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (), } } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 3fe112d794b44..7c59ce354c01a 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -607,7 +607,7 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); } - Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => { + Rvalue::Cast(CastKind::Misc | CastKind::PointerAddress, ref operand, to_ty) => { let operand = codegen_operand(fx, operand); let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index fd29c9e281b92..bd88aa33372df 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -181,6 +181,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty)); let val = match *kind { + mir::CastKind::PointerAddress => { + assert!(bx.cx().is_backend_immediate(cast)); + let llptr = operand.immediate(); + let llcast_ty = bx.cx().immediate_backend_type(cast); + let lladdr = bx.ptrtoint(llptr, llcast_ty); + OperandValue::Immediate(lladdr) + } mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { match *operand.layout.ty.kind() { ty::FnDef(def_id, substs) => { @@ -362,9 +369,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => { bx.pointercast(llval, ll_t_out) } - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - bx.ptrtoint(llval, ll_t_out) - } (CastTy::Int(_), CastTy::Ptr(_)) => { let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed); bx.inttoptr(usize_llval, ll_t_out) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index be34a77bdba96..af563c1450ea0 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,3 +1,4 @@ +use std::assert_matches::assert_matches; use std::convert::TryFrom; use rustc_apfloat::ieee::{Double, Single}; @@ -30,6 +31,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.unsize_into(src, cast_ty, dest)?; } + PointerAddress => { + let src = self.read_immediate(src)?; + let res = self.pointer_address_cast(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + Misc => { let src = self.read_immediate(src)?; let res = self.misc_cast(&src, cast_ty)?; @@ -174,23 +181,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # The remaining source values are scalar and "int-like". let scalar = src.to_scalar()?; + Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) + } - // If we are casting from a pointer to something - // that is not a pointer, mark the pointer as exposed - if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() { - let ptr = self.scalar_to_ptr(scalar)?; - - match ptr.into_pointer_or_addr() { - Ok(ptr) => { - M::expose_ptr(self, ptr)?; - } - Err(_) => { - // do nothing, exposing an invalid pointer - // has no meaning - } - }; - } + pub fn pointer_address_cast( + &mut self, + src: &ImmTy<'tcx, M::PointerTag>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate> { + assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_)); + assert!(cast_ty.is_integral()); + let scalar = src.to_scalar()?; + let ptr = self.scalar_to_ptr(scalar)?; + match ptr.into_pointer_or_addr() { + Ok(ptr) => M::expose_ptr(self, ptr)?, + Err(_) => {} // do nothing, exposing an invalid pointer has no meaning + }; Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index eea6e2a47a94b..4ef33d62a6bfe 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -8,7 +8,6 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable}; @@ -543,16 +542,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // in the type of any local, which also excludes casts). } - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - self.check_op(ops::RawPtrToIntCast); - } + Rvalue::Cast(CastKind::PointerAddress, _, _) => { + self.check_op(ops::RawPtrToIntCast); } + Rvalue::Cast(CastKind::Misc, _, _) => {} + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} Rvalue::ShallowInitBox(_, _) => {} diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index fc6b8a1a7234c..ea23bd14d2538 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -16,7 +16,6 @@ use rustc_hir as hir; use rustc_middle::mir::traversal::ReversePostorderIter; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable}; use rustc_span::Span; @@ -502,18 +501,11 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), - Rvalue::Cast(kind, operand, cast_ty) => { - if matches!(kind, CastKind::Misc) { - let operand_ty = operand.ty(self.body, self.tcx); - let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast"); - if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { - // ptr-to-int casts are not possible in consts and thus not promotable - return Err(Unpromotable); - } - // int-to-ptr casts are fine, they just use the integer value at pointer type. - } + // ptr-to-int casts are not possible in consts and thus not promotable + Rvalue::Cast(CastKind::PointerAddress, _, _) => return Err(Unpromotable), + // int-to-ptr casts are fine, they just use the integer value at pointer type. + Rvalue::Cast(_, operand, _) => { self.validate_operand(operand)?; } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index b09d39996f4de..1b63c8d67ca14 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2604,9 +2604,19 @@ pub enum Rvalue<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Rvalue<'_>, 40); +impl<'tcx> Rvalue<'tcx> { + #[inline] + pub fn is_pointer_int_cast(&self) -> bool { + matches!(self, Rvalue::Cast(CastKind::PointerAddress, _, _)) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum CastKind { Misc, + /// A pointer to address cast. A cast between a pointer and an integer type, + /// or between a function pointer and an integer type. + PointerAddress, Pointer(PointerCast), } diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f1fb484a801ba..c93b7a9550229 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -4,7 +4,6 @@ */ use crate::mir::*; -use crate::ty::cast::CastTy; use crate::ty::subst::Subst; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; @@ -224,22 +223,6 @@ impl<'tcx> Rvalue<'tcx> { _ => RvalueInitializationState::Deep, } } - - pub fn is_pointer_int_cast(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> bool - where - D: HasLocalDecls<'tcx>, - { - if let Rvalue::Cast(CastKind::Misc, src_op, dest_ty) = self { - if let Some(CastTy::Int(_)) = CastTy::from_ty(*dest_ty) { - let src_ty = src_op.ty(local_decls, tcx); - if let Some(CastTy::FnPtr | CastTy::Ptr(_)) = CastTy::from_ty(src_ty) { - return true; - } - } - } - - false - } } impl<'tcx> Operand<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 0a0c7659b086d..2b137046c7f73 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -11,6 +11,7 @@ use rustc_middle::mir::AssertKind; use rustc_middle::mir::Place; use rustc_middle::mir::*; use rustc_middle::thir::*; +use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; @@ -188,11 +189,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { + let source = &this.thir[source]; + let from_ty = CastTy::from_ty(source.ty); + let cast_ty = CastTy::from_ty(expr.ty); + let cast_kind = match (from_ty, cast_ty) { + (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { + CastKind::PointerAddress + } + (_, _) => CastKind::Misc, + }; let source = unpack!( - block = - this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No) + block = this.as_operand(block, scope, source, None, NeedsTemporary::No) ); - block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) + block.and(Rvalue::Cast(cast_kind, source, expr.ty)) } ExprKind::Pointer { cast, source } => { let source = unpack!( diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 4350eb6cdd3b1..7076fbe1bdb53 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -1,7 +1,6 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, Local, LocalDecls, Location, Place, StatementKind}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::mir::{self, Local, Location, Place, StatementKind}; use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis}; @@ -193,27 +192,21 @@ impl DefUse { /// This is basically written for dead store elimination and nothing else. /// /// All of the caveats of `MaybeLiveLocals` apply. -pub struct MaybeTransitiveLiveLocals<'a, 'tcx> { +pub struct MaybeTransitiveLiveLocals<'a> { always_live: &'a BitSet, - local_decls: &'a LocalDecls<'tcx>, - tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> MaybeTransitiveLiveLocals<'a, 'tcx> { +impl<'a> MaybeTransitiveLiveLocals<'a> { /// The `always_alive` set is the set of locals to which all stores should unconditionally be /// considered live. /// /// This should include at least all locals that are ever borrowed. - pub fn new( - always_live: &'a BitSet, - local_decls: &'a LocalDecls<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> Self { - MaybeTransitiveLiveLocals { always_live, local_decls, tcx } + pub fn new(always_live: &'a BitSet) -> Self { + MaybeTransitiveLiveLocals { always_live } } } -impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> { +impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> { type Domain = ChunkedBitSet; type Direction = Backward; @@ -241,7 +234,7 @@ impl<'a> GenKill for TransferWrapper<'a> { } } -impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> { +impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { fn apply_statement_effect( &self, trans: &mut Self::Domain, @@ -251,7 +244,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> { // Compute the place that we are storing to, if any let destination = match &statement.kind { StatementKind::Assign(assign) => { - if assign.1.is_pointer_int_cast(self.local_decls, self.tcx) { + if assign.1.is_pointer_int_cast() { // Pointer to int casts may be side-effects due to exposing the provenance. // While the model is undecided, we should be conservative. See // diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 84f2ee639e4d8..8becac34ed7ee 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -24,7 +24,7 @@ use rustc_mir_dataflow::{impls::MaybeTransitiveLiveLocals, Analysis}; /// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It /// can be generated via the [`get_borrowed_locals`] function. pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet) { - let mut live = MaybeTransitiveLiveLocals::new(borrowed, &body.local_decls, tcx) + let mut live = MaybeTransitiveLiveLocals::new(borrowed) .into_engine(tcx, body) .iterate_to_fixpoint() .into_results_cursor(body); @@ -34,7 +34,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() { let loc = Location { block: bb, statement_index }; if let StatementKind::Assign(assign) = &statement.kind { - if assign.1.is_pointer_int_cast(&body.local_decls, tcx) { + if assign.1.is_pointer_int_cast() { continue; } } diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index c3c1d0c92a86b..839088eac21ea 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -166,9 +166,10 @@ mod tests; /// item's ordering relative to any other item, as determined by the [`Ord`] /// trait, changes while it is in the heap. This is normally only possible /// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The -/// behavior resulting from such a logic error is not specified (it -/// could include panics, incorrect results, aborts, memory leaks, or -/// non-termination) but will not be undefined behavior. +/// behavior resulting from such a logic error is not specified, but will +/// be encapsulated to the `BinaryHeap` that observed the logic error and not +/// result in undefined behavior. This could include panics, incorrect results, +/// aborts, memory leaks, and non-termination. /// /// # Examples /// diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 264c217c9ef23..6027991a0ed2f 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -64,9 +64,9 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// It is a logic error for a key to be modified in such a way that the key's ordering relative to /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. -/// The behavior resulting from such a logic error is not specified (it could include panics, -/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined -/// behavior. +/// The behavior resulting from such a logic error is not specified, but will be encapsulated to the +/// `BTreeMap` that observed the logic error and not result in undefined behavior. This could +/// include panics, incorrect results, aborts, memory leaks, and non-termination. /// /// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or /// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index d6733425288d4..20ef834eaeef3 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -23,9 +23,9 @@ use super::Recover; /// It is a logic error for an item to be modified in such a way that the item's ordering relative /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. -/// The behavior resulting from such a logic error is not specified (it could include panics, -/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined -/// behavior. +/// The behavior resulting from such a logic error is not specified, but will be encapsulated to the +/// `BTreeSet` that observed the logic error and not result in undefined behavior. This could +/// include panics, incorrect results, aborts, memory leaks, and non-termination. /// /// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case /// logarithmic and amortized constant time per item returned. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 0f0692eed494e..45947c4f4a584 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2472,7 +2472,7 @@ impl ExtendFromWithinSpec for Vec { // SAFETY: // - Both pointers are created from unique slice references (`&mut [_]`) // so they are valid and do not overlap. - // - Elements are :Copy so it's OK to to copy them, without doing + // - Elements are :Copy so it's OK to copy them, without doing // anything with the original values // - `count` is equal to the len of `source`, so source is valid for // `count` reads diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 969f5dde4f05d..4ec423eb27f31 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -54,7 +54,8 @@ use crate::sys; /// the [`Eq`] trait, changes while it is in the map. This is normally only /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// The behavior resulting from such a logic error is not specified, but will -/// not result in undefined behavior. This could include panics, incorrect results, +/// be encapsulated to the `HashMap` that observed the logic error and not +/// result in undefined behavior. This could include panics, incorrect results, /// aborts, memory leaks, and non-termination. /// /// The hash table implementation is a Rust port of Google's [SwissTable]. diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 4ac0e081c2e2d..da0572047eca8 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -33,13 +33,14 @@ use super::map::{map_try_reserve_error, RandomState}; /// In other words, if two keys are equal, their hashes must be equal. /// /// -/// It is a logic error for an item to be modified in such a way that the -/// item's hash, as determined by the [`Hash`] trait, or its equality, as -/// determined by the [`Eq`] trait, changes while it is in the set. This is -/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or -/// unsafe code. The behavior resulting from such a logic error is not -/// specified (it could include panics, incorrect results, aborts, memory -/// leaks, or non-termination) but will not be undefined behavior. +/// It is a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// The behavior resulting from such a logic error is not specified, but will +/// be encapsulated to the `HashSet` that observed the logic error and not +/// result in undefined behavior. This could include panics, incorrect results, +/// aborts, memory leaks, and non-termination. /// /// # Examples /// diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index 466c286c9d7c9..4fdd4b2b4bb86 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -21,7 +21,7 @@ // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 + _1 = move _2 as usize (PointerAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 StorageDead(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:39: 7:40 StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff index 1aeeae91d203f..7eb34ed5469ba 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff @@ -17,7 +17,7 @@ // mir::Constant // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17 // + literal: Const { ty: fn() {main}, val: Value(Scalar()) } - _2 = move _3 as usize (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 + _2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26 _1 = move _2 as *const fn() (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41 diff --git a/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff index 2250159c81667..bf32245e30098 100644 --- a/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff @@ -19,12 +19,12 @@ StorageLive(_2); // scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11 StorageLive(_3); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15 _3 = _1; // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15 - _2 = move _3 as usize (Misc); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24 + _2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24 StorageDead(_3); // scope 0 at $DIR/provenance_soundness.rs:8:23: 8:24 StorageLive(_4); // scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11 StorageLive(_5); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15 _5 = _1; // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15 - _4 = move _5 as isize (Misc); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24 + _4 = move _5 as isize (PointerAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24 StorageDead(_5); // scope 1 at $DIR/provenance_soundness.rs:9:23: 9:24 _0 = const (); // scope 0 at $DIR/provenance_soundness.rs:7:32: 10:2 StorageDead(_4); // scope 1 at $DIR/provenance_soundness.rs:10:1: 10:2 diff --git a/src/test/ui/borrowck/issue-71546.rs b/src/test/ui/borrowck/issue-71546.rs new file mode 100644 index 0000000000000..4486ec5b081e3 --- /dev/null +++ b/src/test/ui/borrowck/issue-71546.rs @@ -0,0 +1,16 @@ +// Regression test for #71546. + +pub fn serialize_as_csv(value: &V) -> Result +where + V: 'static, + for<'a> &'a V: IntoIterator, + for<'a> <&'a V as IntoIterator>::Item: ToString + 'static, +{ + let csv_str: String = value //~ ERROR: the associated type `<&'a V as IntoIterator>::Item` may not live long enough + .into_iter() + .map(|elem| elem.to_string()) + .collect::(); + Ok(csv_str) +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-71546.stderr b/src/test/ui/borrowck/issue-71546.stderr new file mode 100644 index 0000000000000..a3136b6298621 --- /dev/null +++ b/src/test/ui/borrowck/issue-71546.stderr @@ -0,0 +1,20 @@ +error[E0310]: the associated type `<&'a V as IntoIterator>::Item` may not live long enough + --> $DIR/issue-71546.rs:9:27 + | +LL | let csv_str: String = value + | ___________________________^ +LL | | .into_iter() +LL | | .map(|elem| elem.to_string()) + | |_____________________________________^ + | + = help: consider adding an explicit lifetime bound `<&'a V as IntoIterator>::Item: 'static`... + = note: ...so that the type `<&'a V as IntoIterator>::Item` will meet its required lifetime bounds... +note: ...that is required by this bound + --> $DIR/issue-71546.rs:7:55 + | +LL | for<'a> <&'a V as IntoIterator>::Item: ToString + 'static, + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 78d8f1e213af0..283b20fc24d82 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -125,16 +125,11 @@ fn check_rvalue<'tcx>( Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { check_place(tcx, *place, span, body) }, - Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { - use rustc_middle::ty::cast::CastTy; - let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - Err((span, "casting pointers to ints is unstable in const fn".into())) - }, - _ => check_operand(tcx, operand, span, body), - } + Rvalue::Cast(CastKind::PointerAddress, _, _) => { + Err((span, "casting pointers to ints is unstable in const fn".into())) + }, + Rvalue::Cast(CastKind::Misc, operand, _) => { + check_operand(tcx, operand, span, body) }, Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => { check_operand(tcx, operand, span, body)