Auto merge of #124084 - matthiaskrgr:rollup-h42psbx, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - #116957 (meta: notify #t-rustdoc Zulip stream on backport nominations)
 - #122201 (Document overrides of `clone_from()` in core/std)
 - #122723 (Use same file permissions for ar_archive_writer as the LLVM archive writer)
 - #124030 (interpret: pass MemoryKind to adjust_alloc_base_pointer)
 - #124037 (Don't ascend into parent bodies when collecting stmts for possible return suggestion)
 - #124049 (Stabilize `const_io_structs`)
 - #124062 (Add another expression to weird-exprs.rs)
 - #124066 (Don't error on subtyping of equal types)
 - #124073 (Remove libc from rust_get_test_int uses)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-04-17 16:27:58 +00:00
commit c45dee5efd
48 changed files with 402 additions and 162 deletions

View file

@ -13,7 +13,7 @@ use object::read::macho::FatArch;
use tempfile::Builder as TempFileBuilder; use tempfile::Builder as TempFileBuilder;
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::{self, File};
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -280,12 +280,21 @@ impl<'a> ArArchiveBuilder<'a> {
// This prevents programs (including rustc) from attempting to read a partial archive. // This prevents programs (including rustc) from attempting to read a partial archive.
// It also enables writing an archive with the same filename as a dependency on Windows as // It also enables writing an archive with the same filename as a dependency on Windows as
// required by a test. // required by a test.
let mut archive_tmpfile = TempFileBuilder::new() // The tempfile crate currently uses 0o600 as mode for the temporary files and directories
// it creates. We need it to be the default mode for back compat reasons however. (See
// #107495) To handle this we are telling tempfile to create a temporary directory instead
// and then inside this directory create a file using File::create.
let archive_tmpdir = TempFileBuilder::new()
.suffix(".temp-archive") .suffix(".temp-archive")
.tempfile_in(output.parent().unwrap_or_else(|| Path::new(""))) .tempdir_in(output.parent().unwrap_or_else(|| Path::new("")))
.map_err(|err| io_error_context("couldn't create a temp file", err))?; .map_err(|err| {
io_error_context("couldn't create a directory for the temp file", err)
})?;
let archive_tmpfile_path = archive_tmpdir.path().join("tmp.a");
let mut archive_tmpfile = File::create_new(&archive_tmpfile_path)
.map_err(|err| io_error_context("couldn't create the temp file", err))?;
write_archive_to_stream(archive_tmpfile.as_file_mut(), &entries, archive_kind, false)?; write_archive_to_stream(&mut archive_tmpfile, &entries, archive_kind, false)?;
let any_entries = !entries.is_empty(); let any_entries = !entries.is_empty();
drop(entries); drop(entries);
@ -293,9 +302,11 @@ impl<'a> ArArchiveBuilder<'a> {
// output archive to the same location as an input archive on Windows. // output archive to the same location as an input archive on Windows.
drop(self.src_archives); drop(self.src_archives);
archive_tmpfile fs::rename(archive_tmpfile_path, output)
.persist(output) .map_err(|err| io_error_context("failed to rename archive file", err))?;
.map_err(|err| io_error_context("failed to rename archive file", err.error))?; archive_tmpdir
.close()
.map_err(|err| io_error_context("failed to remove temporary directory", err))?;
Ok(any_entries) Ok(any_entries)
} }

View file

@ -288,28 +288,19 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
} }
/// Return the `AllocId` for the given thread-local static in the current thread. /// Return the `AllocId` for the given thread-local static in the current thread.
fn thread_local_static_base_pointer( fn thread_local_static_pointer(
_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ecx: &mut InterpCx<'mir, 'tcx, Self>,
def_id: DefId, def_id: DefId,
) -> InterpResult<'tcx, Pointer<Self::Provenance>> { ) -> InterpResult<'tcx, Pointer<Self::Provenance>> {
throw_unsup!(ThreadLocalStatic(def_id)) throw_unsup!(ThreadLocalStatic(def_id))
} }
/// Return the root pointer for the given `extern static`. /// Return the `AllocId` for the given `extern static`.
fn extern_static_base_pointer( fn extern_static_pointer(
ecx: &InterpCx<'mir, 'tcx, Self>, ecx: &InterpCx<'mir, 'tcx, Self>,
def_id: DefId, def_id: DefId,
) -> InterpResult<'tcx, Pointer<Self::Provenance>>; ) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
/// Return a "base" pointer for the given allocation: the one that is used for direct
/// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
///
/// Not called on `extern` or thread-local statics (those use the methods above).
fn adjust_alloc_base_pointer(
ecx: &InterpCx<'mir, 'tcx, Self>,
ptr: Pointer,
) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
/// "Int-to-pointer cast" /// "Int-to-pointer cast"
fn ptr_from_addr_cast( fn ptr_from_addr_cast(
ecx: &InterpCx<'mir, 'tcx, Self>, ecx: &InterpCx<'mir, 'tcx, Self>,
@ -336,6 +327,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// Called to adjust allocations to the Provenance and AllocExtra of this machine. /// Called to adjust allocations to the Provenance and AllocExtra of this machine.
/// ///
/// If `alloc` contains pointers, then they are all pointing to globals.
///
/// The way we construct allocations is to always first construct it without extra and then add /// The way we construct allocations is to always first construct it without extra and then add
/// the extra. This keeps uniform code paths for handling both allocations created by CTFE for /// the extra. This keeps uniform code paths for handling both allocations created by CTFE for
/// globals, and allocations created by Miri during evaluation. /// globals, and allocations created by Miri during evaluation.
@ -354,6 +347,19 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
kind: Option<MemoryKind<Self::MemoryKind>>, kind: Option<MemoryKind<Self::MemoryKind>>,
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>; ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
/// Return a "root" pointer for the given allocation: the one that is used for direct
/// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
///
/// Not called on `extern` or thread-local statics (those use the methods above).
///
/// `kind` is the kind of the allocation the pointer points to; it can be `None` when
/// it's a global and `GLOBAL_KIND` is `None`.
fn adjust_alloc_root_pointer(
ecx: &InterpCx<'mir, 'tcx, Self>,
ptr: Pointer,
kind: Option<MemoryKind<Self::MemoryKind>>,
) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
/// Evaluate the inline assembly. /// Evaluate the inline assembly.
/// ///
/// This should take care of jumping to the next block (one of `targets`) when asm goto /// This should take care of jumping to the next block (one of `targets`) when asm goto
@ -592,7 +598,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
Ok(alloc) Ok(alloc)
} }
fn extern_static_base_pointer( fn extern_static_pointer(
ecx: &InterpCx<$mir, $tcx, Self>, ecx: &InterpCx<$mir, $tcx, Self>,
def_id: DefId, def_id: DefId,
) -> InterpResult<$tcx, Pointer> { ) -> InterpResult<$tcx, Pointer> {
@ -601,9 +607,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
} }
#[inline(always)] #[inline(always)]
fn adjust_alloc_base_pointer( fn adjust_alloc_root_pointer(
_ecx: &InterpCx<$mir, $tcx, Self>, _ecx: &InterpCx<$mir, $tcx, Self>,
ptr: Pointer<CtfeProvenance>, ptr: Pointer<CtfeProvenance>,
_kind: Option<MemoryKind<Self::MemoryKind>>,
) -> InterpResult<$tcx, Pointer<CtfeProvenance>> { ) -> InterpResult<$tcx, Pointer<CtfeProvenance>> {
Ok(ptr) Ok(ptr)
} }

View file

@ -165,7 +165,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// ///
/// This function can fail only if `ptr` points to an `extern static`. /// This function can fail only if `ptr` points to an `extern static`.
#[inline] #[inline]
pub fn global_base_pointer( pub fn global_root_pointer(
&self, &self,
ptr: Pointer<CtfeProvenance>, ptr: Pointer<CtfeProvenance>,
) -> InterpResult<'tcx, Pointer<M::Provenance>> { ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
@ -178,12 +178,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
bug!("global memory cannot point to thread-local static") bug!("global memory cannot point to thread-local static")
} }
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => { Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => {
return M::extern_static_base_pointer(self, def_id); return M::extern_static_pointer(self, def_id);
}
None => {
assert!(
self.memory.extra_fn_ptr_map.contains_key(&alloc_id),
"{alloc_id:?} is neither global nor a function pointer"
);
} }
_ => {} _ => {}
} }
// And we need to get the provenance. // And we need to get the provenance.
M::adjust_alloc_base_pointer(self, ptr) M::adjust_alloc_root_pointer(self, ptr, M::GLOBAL_KIND.map(MemoryKind::Machine))
} }
pub fn fn_ptr(&mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>) -> Pointer<M::Provenance> { pub fn fn_ptr(&mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>) -> Pointer<M::Provenance> {
@ -197,9 +203,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
id id
} }
}; };
// Functions are global allocations, so make sure we get the right base pointer. // Functions are global allocations, so make sure we get the right root pointer.
// We know this is not an `extern static` so this cannot fail. // We know this is not an `extern static` so this cannot fail.
self.global_base_pointer(Pointer::from(id)).unwrap() self.global_root_pointer(Pointer::from(id)).unwrap()
} }
pub fn allocate_ptr( pub fn allocate_ptr(
@ -240,7 +246,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
); );
let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?; let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
self.memory.alloc_map.insert(id, (kind, alloc.into_owned())); self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
M::adjust_alloc_base_pointer(self, Pointer::from(id)) M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
} }
pub fn reallocate_ptr( pub fn reallocate_ptr(

View file

@ -764,7 +764,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Other cases need layout. // Other cases need layout.
let adjust_scalar = |scalar| -> InterpResult<'tcx, _> { let adjust_scalar = |scalar| -> InterpResult<'tcx, _> {
Ok(match scalar { Ok(match scalar {
Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_base_pointer(ptr)?, size), Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_root_pointer(ptr)?, size),
Scalar::Int(int) => Scalar::Int(int), Scalar::Int(int) => Scalar::Int(int),
}) })
}; };
@ -772,7 +772,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let imm = match val_val { let imm = match val_val {
mir::ConstValue::Indirect { alloc_id, offset } => { mir::ConstValue::Indirect { alloc_id, offset } => {
// This is const data, no mutation allowed. // This is const data, no mutation allowed.
let ptr = self.global_base_pointer(Pointer::new( let ptr = self.global_root_pointer(Pointer::new(
CtfeProvenance::from(alloc_id).as_immutable(), CtfeProvenance::from(alloc_id).as_immutable(),
offset, offset,
))?; ))?;
@ -784,7 +784,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// This is const data, no mutation allowed. // This is const data, no mutation allowed.
let alloc_id = self.tcx.reserve_and_set_memory_alloc(data); let alloc_id = self.tcx.reserve_and_set_memory_alloc(data);
let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO); let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO);
Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self) Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self)
} }
}; };
Ok(OpTy { op: Operand::Immediate(imm), layout }) Ok(OpTy { op: Operand::Immediate(imm), layout })

View file

@ -1010,7 +1010,7 @@ where
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
// This must be an allocation in `tcx` // This must be an allocation in `tcx`
let _ = self.tcx.global_alloc(raw.alloc_id); let _ = self.tcx.global_alloc(raw.alloc_id);
let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; let ptr = self.global_root_pointer(Pointer::from(raw.alloc_id))?;
let layout = self.layout_of(raw.ty)?; let layout = self.layout_of(raw.ty)?;
Ok(self.ptr_to_mplace(ptr.into(), layout)) Ok(self.ptr_to_mplace(ptr.into(), layout))
} }

View file

@ -144,7 +144,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
use rustc_middle::mir::Rvalue::*; use rustc_middle::mir::Rvalue::*;
match *rvalue { match *rvalue {
ThreadLocalRef(did) => { ThreadLocalRef(did) => {
let ptr = M::thread_local_static_base_pointer(self, did)?; let ptr = M::thread_local_static_pointer(self, did)?;
self.write_pointer(ptr, &dest)?; self.write_pointer(ptr, &dest)?;
} }

View file

@ -28,7 +28,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref); let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, poly_trait_ref);
let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?; let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?;
Ok(vtable_ptr.into()) Ok(vtable_ptr.into())
} }

View file

@ -2011,12 +2011,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (span, code) in errors_causecode { for (span, code) in errors_causecode {
self.dcx().try_steal_modify_and_emit_err(span, StashKey::MaybeForgetReturn, |err| { self.dcx().try_steal_modify_and_emit_err(span, StashKey::MaybeForgetReturn, |err| {
if let Some(fn_sig) = self.body_fn_sig() if let Some(fn_sig) = self.body_fn_sig()
&& let ExprBindingObligation(_, _, hir_id, ..) = code && let ExprBindingObligation(_, _, binding_hir_id, ..) = code
&& !fn_sig.output().is_unit() && !fn_sig.output().is_unit()
{ {
let mut block_num = 0; let mut block_num = 0;
let mut found_semi = false; let mut found_semi = false;
for (_, node) in self.tcx.hir().parent_iter(hir_id) { for (hir_id, node) in self.tcx.hir().parent_iter(binding_hir_id) {
// Don't proceed into parent bodies
if hir_id.owner != binding_hir_id.owner {
break;
}
match node { match node {
hir::Node::Stmt(stmt) => { hir::Node::Stmt(stmt) => {
if let hir::StmtKind::Semi(expr) = stmt.kind { if let hir::StmtKind::Semi(expr) = stmt.kind {

View file

@ -952,7 +952,7 @@ impl<'tcx> InferCtxt<'tcx> {
// a test for it. // a test for it.
(_, ty::Infer(ty::TyVar(_))) => {} (_, ty::Infer(ty::TyVar(_))) => {}
(ty::Infer(ty::TyVar(_)), _) => {} (ty::Infer(ty::TyVar(_)), _) => {}
_ if (r_a, r_b).has_opaque_types() => { _ if r_a != r_b && (r_a, r_b).has_opaque_types() => {
span_bug!( span_bug!(
cause.span(), cause.span(),
"opaque types got hidden types registered from within subtype predicate: {r_a:?} vs {r_b:?}" "opaque types got hidden types registered from within subtype predicate: {r_a:?} vs {r_b:?}"

View file

@ -2088,11 +2088,29 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
self.to_vec_in(alloc).into_boxed_slice() self.to_vec_in(alloc).into_boxed_slice()
} }
fn clone_from(&mut self, other: &Self) { /// Copies `source`'s contents into `self` without creating a new allocation,
if self.len() == other.len() { /// so long as the two are of the same length.
self.clone_from_slice(&other); ///
/// # Examples
///
/// ```
/// let x = Box::new([5, 6, 7]);
/// let mut y = Box::new([8, 9, 10]);
/// let yp: *const [i32] = &*y;
///
/// y.clone_from(&x);
///
/// // The value is the same
/// assert_eq!(x, y);
///
/// // And no allocation occurred
/// assert_eq!(yp, &*y);
/// ```
fn clone_from(&mut self, source: &Self) {
if self.len() == source.len() {
self.clone_from_slice(&source);
} else { } else {
*self = other.clone(); *self = source.clone();
} }
} }
} }

View file

@ -385,6 +385,12 @@ impl<T: Clone, A: Allocator + Clone> Clone for BinaryHeap<T, A> {
BinaryHeap { data: self.data.clone() } BinaryHeap { data: self.data.clone() }
} }
/// Overwrites the contents of `self` with a clone of the contents of `source`.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids reallocation if possible.
///
/// See [`Vec::clone_from()`] for more details.
fn clone_from(&mut self, source: &Self) { fn clone_from(&mut self, source: &Self) {
self.data.clone_from(&source.data); self.data.clone_from(&source.data);
} }

View file

@ -116,8 +116,8 @@ impl<T: Clone, A: Allocator + Clone> Clone for BTreeSet<T, A> {
BTreeSet { map: self.map.clone() } BTreeSet { map: self.map.clone() }
} }
fn clone_from(&mut self, other: &Self) { fn clone_from(&mut self, source: &Self) {
self.map.clone_from(&other.map); self.map.clone_from(&source.map);
} }
} }

View file

@ -2126,16 +2126,22 @@ impl<T: Clone, A: Allocator + Clone> Clone for LinkedList<T, A> {
list list
} }
fn clone_from(&mut self, other: &Self) { /// Overwrites the contents of `self` with a clone of the contents of `source`.
let mut iter_other = other.iter(); ///
if self.len() > other.len() { /// This method is preferred over simply assigning `source.clone()` to `self`,
self.split_off(other.len()); /// as it avoids reallocation of the nodes of the linked list. Additionally,
/// if the element type `T` overrides `clone_from()`, this will reuse the
/// resources of `self`'s elements as well.
fn clone_from(&mut self, source: &Self) {
let mut source_iter = source.iter();
if self.len() > source.len() {
self.split_off(source.len());
} }
for (elem, elem_other) in self.iter_mut().zip(&mut iter_other) { for (elem, source_elem) in self.iter_mut().zip(&mut source_iter) {
elem.clone_from(elem_other); elem.clone_from(source_elem);
} }
if !iter_other.is_empty() { if !source_iter.is_empty() {
self.extend(iter_other.cloned()); self.extend(source_iter.cloned());
} }
} }
} }

View file

@ -113,9 +113,13 @@ impl<T: Clone, A: Allocator + Clone> Clone for VecDeque<T, A> {
deq deq
} }
fn clone_from(&mut self, other: &Self) { /// Overwrites the contents of `self` with a clone of the contents of `source`.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids reallocation if possible.
fn clone_from(&mut self, source: &Self) {
self.clear(); self.clear();
self.extend(other.iter().cloned()); self.extend(source.iter().cloned());
} }
} }

View file

@ -2097,6 +2097,10 @@ impl Clone for String {
String { vec: self.vec.clone() } String { vec: self.vec.clone() }
} }
/// Clones the contents of `source` into `self`.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids reallocation if possible.
fn clone_from(&mut self, source: &Self) { fn clone_from(&mut self, source: &Self) {
self.vec.clone_from(&source.vec); self.vec.clone_from(&source.vec);
} }

View file

@ -2846,8 +2846,30 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
crate::slice::to_vec(&**self, alloc) crate::slice::to_vec(&**self, alloc)
} }
fn clone_from(&mut self, other: &Self) { /// Overwrites the contents of `self` with a clone of the contents of `source`.
crate::slice::SpecCloneIntoVec::clone_into(other.as_slice(), self); ///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids reallocation if possible. Additionally, if the element type
/// `T` overrides `clone_from()`, this will reuse the resources of `self`'s
/// elements as well.
///
/// # Examples
///
/// ```
/// let x = vec![5, 6, 7];
/// let mut y = vec![8, 9, 10];
/// let yp: *const i32 = y.as_ptr();
///
/// y.clone_from(&x);
///
/// // The value is the same
/// assert_eq!(x, y);
///
/// // And no reallocation occurred
/// assert_eq!(yp, y.as_ptr());
/// ```
fn clone_from(&mut self, source: &Self) {
crate::slice::SpecCloneIntoVec::clone_into(source.as_slice(), self);
} }
} }

View file

@ -1277,11 +1277,11 @@ impl<T: Clone> Clone for RefCell<T> {
/// # Panics /// # Panics
/// ///
/// Panics if `other` is currently mutably borrowed. /// Panics if `source` is currently mutably borrowed.
#[inline] #[inline]
#[track_caller] #[track_caller]
fn clone_from(&mut self, other: &Self) { fn clone_from(&mut self, source: &Self) {
self.get_mut().clone_from(&other.borrow()) self.get_mut().clone_from(&source.borrow())
} }
} }

View file

@ -688,8 +688,8 @@ impl<T: Clone> Clone for Reverse<T> {
} }
#[inline] #[inline]
fn clone_from(&mut self, other: &Self) { fn clone_from(&mut self, source: &Self) {
self.0.clone_from(&other.0) self.0.clone_from(&source.0)
} }
} }

View file

@ -576,6 +576,42 @@ impl Clone for Waker {
} }
} }
/// Assigns a clone of `source` to `self`, unless [`self.will_wake(source)`][Waker::will_wake] anyway.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids cloning the waker if `self` is already the same waker.
///
/// # Examples
///
/// ```
/// use std::future::Future;
/// use std::pin::Pin;
/// use std::sync::{Arc, Mutex};
/// use std::task::{Context, Poll, Waker};
///
/// struct Waiter {
/// shared: Arc<Mutex<Shared>>,
/// }
///
/// struct Shared {
/// waker: Waker,
/// // ...
/// }
///
/// impl Future for Waiter {
/// type Output = ();
/// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
/// let mut shared = self.shared.lock().unwrap();
///
/// // update the waker
/// shared.waker.clone_from(cx.waker());
///
/// // readiness logic ...
/// # Poll::Ready(())
/// }
/// }
///
/// ```
#[inline] #[inline]
fn clone_from(&mut self, source: &Self) { fn clone_from(&mut self, source: &Self) {
if !self.will_wake(source) { if !self.will_wake(source) {

View file

@ -1271,8 +1271,8 @@ where
} }
#[inline] #[inline]
fn clone_from(&mut self, other: &Self) { fn clone_from(&mut self, source: &Self) {
self.base.clone_from(&other.base); self.base.clone_from(&source.base);
} }
} }

View file

@ -978,6 +978,10 @@ where
Self { base: self.base.clone() } Self { base: self.base.clone() }
} }
/// Overwrites the contents of `self` with a clone of the contents of `source`.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids reallocation if possible.
#[inline] #[inline]
fn clone_from(&mut self, other: &Self) { fn clone_from(&mut self, other: &Self) {
self.base.clone_from(&other.base); self.base.clone_from(&other.base);

View file

@ -606,6 +606,10 @@ impl Clone for OsString {
OsString { inner: self.inner.clone() } OsString { inner: self.inner.clone() }
} }
/// Clones the contents of `source` into `self`.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids reallocation if possible.
#[inline] #[inline]
fn clone_from(&mut self, source: &Self) { fn clone_from(&mut self, source: &Self) {
self.inner.clone_from(&source.inner) self.inner.clone_from(&source.inner)

View file

@ -95,7 +95,7 @@ impl<T> Cursor<T> {
/// # force_inference(&buff); /// # force_inference(&buff);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")]
pub const fn new(inner: T) -> Cursor<T> { pub const fn new(inner: T) -> Cursor<T> {
Cursor { pos: 0, inner } Cursor { pos: 0, inner }
} }
@ -132,7 +132,7 @@ impl<T> Cursor<T> {
/// let reference = buff.get_ref(); /// let reference = buff.get_ref();
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")]
pub const fn get_ref(&self) -> &T { pub const fn get_ref(&self) -> &T {
&self.inner &self.inner
} }
@ -178,7 +178,7 @@ impl<T> Cursor<T> {
/// assert_eq!(buff.position(), 1); /// assert_eq!(buff.position(), 1);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")]
pub const fn position(&self) -> u64 { pub const fn position(&self) -> u64 {
self.pos self.pos
} }

View file

@ -51,7 +51,7 @@ pub struct Empty;
/// ``` /// ```
#[must_use] #[must_use]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")]
pub const fn empty() -> Empty { pub const fn empty() -> Empty {
Empty Empty
} }
@ -173,7 +173,7 @@ pub struct Repeat {
/// ``` /// ```
#[must_use] #[must_use]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")]
pub const fn repeat(byte: u8) -> Repeat { pub const fn repeat(byte: u8) -> Repeat {
Repeat { byte } Repeat { byte }
} }
@ -276,7 +276,7 @@ pub struct Sink;
/// ``` /// ```
#[must_use] #[must_use]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] #[rustc_const_stable(feature = "const_io_structs", since = "CURRENT_RUSTC_VERSION")]
pub const fn sink() -> Sink { pub const fn sink() -> Sink {
Sink Sink
} }

View file

@ -407,7 +407,6 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![feature(const_collections_with_hasher)] #![feature(const_collections_with_hasher)]
#![feature(const_hash)] #![feature(const_hash)]
#![feature(const_io_structs)]
#![feature(const_ip)] #![feature(const_ip)]
#![feature(const_ipv4)] #![feature(const_ipv4)]
#![feature(const_ipv6)] #![feature(const_ipv6)]

View file

@ -1628,6 +1628,10 @@ impl Clone for PathBuf {
PathBuf { inner: self.inner.clone() } PathBuf { inner: self.inner.clone() }
} }
/// Clones the contents of `source` into `self`.
///
/// This method is preferred over simply assigning `source.clone()` to `self`,
/// as it avoids reallocation if possible.
#[inline] #[inline]
fn clone_from(&mut self, source: &Self) { fn clone_from(&mut self, source: &Self) {
self.inner.clone_from(&source.inner) self.inner.clone_from(&source.inner)

View file

@ -141,7 +141,11 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
} }
fn addr_from_alloc_id(&self, alloc_id: AllocId) -> InterpResult<'tcx, u64> { fn addr_from_alloc_id(
&self,
alloc_id: AllocId,
_kind: MemoryKind,
) -> InterpResult<'tcx, u64> {
let ecx = self.eval_context_ref(); let ecx = self.eval_context_ref();
let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); let mut global_state = ecx.machine.alloc_addresses.borrow_mut();
let global_state = &mut *global_state; let global_state = &mut *global_state;
@ -283,16 +287,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} }
/// Convert a relative (tcx) pointer to a Miri pointer. /// Convert a relative (tcx) pointer to a Miri pointer.
fn ptr_from_rel_ptr( fn adjust_alloc_root_pointer(
&self, &self,
ptr: Pointer<CtfeProvenance>, ptr: Pointer<CtfeProvenance>,
tag: BorTag, tag: BorTag,
kind: MemoryKind,
) -> InterpResult<'tcx, Pointer<Provenance>> { ) -> InterpResult<'tcx, Pointer<Provenance>> {
let ecx = self.eval_context_ref(); let ecx = self.eval_context_ref();
let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
let alloc_id = prov.alloc_id(); let alloc_id = prov.alloc_id();
let base_addr = ecx.addr_from_alloc_id(alloc_id)?; let base_addr = ecx.addr_from_alloc_id(alloc_id, kind)?;
// Add offset with the right kind of pointer-overflowing arithmetic. // Add offset with the right kind of pointer-overflowing arithmetic.
let dl = ecx.data_layout(); let dl = ecx.data_layout();
@ -314,9 +319,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
ecx.alloc_id_from_addr(addr.bytes())? ecx.alloc_id_from_addr(addr.bytes())?
}; };
// This cannot fail: since we already have a pointer with that provenance, rel_ptr_to_addr // This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer
// must have been called in the past, so we can just look up the address in the map. // must have been called in the past, so we can just look up the address in the map.
let base_addr = ecx.addr_from_alloc_id(alloc_id).unwrap(); let base_addr = *ecx.machine.alloc_addresses.borrow().base_addr.get(&alloc_id).unwrap();
// Wrapping "addr - base_addr" // Wrapping "addr - base_addr"
#[allow(clippy::cast_possible_wrap)] // we want to wrap here #[allow(clippy::cast_possible_wrap)] // we want to wrap here

View file

@ -89,10 +89,10 @@ pub struct GlobalStateInner {
borrow_tracker_method: BorrowTrackerMethod, borrow_tracker_method: BorrowTrackerMethod,
/// Next unused pointer ID (tag). /// Next unused pointer ID (tag).
next_ptr_tag: BorTag, next_ptr_tag: BorTag,
/// Table storing the "base" tag for each allocation. /// Table storing the "root" tag for each allocation.
/// The base tag is the one used for the initial pointer. /// The root tag is the one used for the initial pointer.
/// We need this in a separate table to handle cyclic statics. /// We need this in a separate table to handle cyclic statics.
base_ptr_tags: FxHashMap<AllocId, BorTag>, root_ptr_tags: FxHashMap<AllocId, BorTag>,
/// Next unused call ID (for protectors). /// Next unused call ID (for protectors).
next_call_id: CallId, next_call_id: CallId,
/// All currently protected tags. /// All currently protected tags.
@ -175,7 +175,7 @@ impl GlobalStateInner {
GlobalStateInner { GlobalStateInner {
borrow_tracker_method, borrow_tracker_method,
next_ptr_tag: BorTag::one(), next_ptr_tag: BorTag::one(),
base_ptr_tags: FxHashMap::default(), root_ptr_tags: FxHashMap::default(),
next_call_id: NonZero::new(1).unwrap(), next_call_id: NonZero::new(1).unwrap(),
protected_tags: FxHashMap::default(), protected_tags: FxHashMap::default(),
tracked_pointer_tags, tracked_pointer_tags,
@ -213,8 +213,8 @@ impl GlobalStateInner {
} }
} }
pub fn base_ptr_tag(&mut self, id: AllocId, machine: &MiriMachine<'_, '_>) -> BorTag { pub fn root_ptr_tag(&mut self, id: AllocId, machine: &MiriMachine<'_, '_>) -> BorTag {
self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| { self.root_ptr_tags.get(&id).copied().unwrap_or_else(|| {
let tag = self.new_ptr(); let tag = self.new_ptr();
if self.tracked_pointer_tags.contains(&tag) { if self.tracked_pointer_tags.contains(&tag) {
machine.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag( machine.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(
@ -223,14 +223,14 @@ impl GlobalStateInner {
None, None,
)); ));
} }
trace!("New allocation {:?} has base tag {:?}", id, tag); trace!("New allocation {:?} has rpot tag {:?}", id, tag);
self.base_ptr_tags.try_insert(id, tag).unwrap(); self.root_ptr_tags.try_insert(id, tag).unwrap();
tag tag
}) })
} }
pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) { pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) {
self.base_ptr_tags.retain(|id, _| allocs.is_live(*id)); self.root_ptr_tags.retain(|id, _| allocs.is_live(*id));
} }
} }

View file

@ -20,7 +20,7 @@ fn err_sb_ub<'tcx>(
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct AllocHistory { pub struct AllocHistory {
id: AllocId, id: AllocId,
base: (Item, Span), root: (Item, Span),
creations: smallvec::SmallVec<[Creation; 1]>, creations: smallvec::SmallVec<[Creation; 1]>,
invalidations: smallvec::SmallVec<[Invalidation; 1]>, invalidations: smallvec::SmallVec<[Invalidation; 1]>,
protectors: smallvec::SmallVec<[Protection; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>,
@ -225,7 +225,7 @@ impl AllocHistory {
pub fn new(id: AllocId, item: Item, machine: &MiriMachine<'_, '_>) -> Self { pub fn new(id: AllocId, item: Item, machine: &MiriMachine<'_, '_>) -> Self {
Self { Self {
id, id,
base: (item, machine.current_span()), root: (item, machine.current_span()),
creations: SmallVec::new(), creations: SmallVec::new(),
invalidations: SmallVec::new(), invalidations: SmallVec::new(),
protectors: SmallVec::new(), protectors: SmallVec::new(),
@ -342,15 +342,15 @@ impl<'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'history, 'ecx, 'mir, 'tcx> {
}) })
}) })
.or_else(|| { .or_else(|| {
// If we didn't find a retag that created this tag, it might be the base tag of // If we didn't find a retag that created this tag, it might be the root tag of
// this allocation. // this allocation.
if self.history.base.0.tag() == tag { if self.history.root.0.tag() == tag {
Some(( Some((
format!( format!(
"{tag:?} was created here, as the base tag for {:?}", "{tag:?} was created here, as the root tag for {:?}",
self.history.id self.history.id
), ),
self.history.base.1.data(), self.history.root.1.data(),
)) ))
} else { } else {
None None

View file

@ -518,9 +518,9 @@ impl Stacks {
// not through a pointer). That is, whenever we directly write to a local, this will pop // not through a pointer). That is, whenever we directly write to a local, this will pop
// everything else off the stack, invalidating all previous pointers, // everything else off the stack, invalidating all previous pointers,
// and in particular, *all* raw pointers. // and in particular, *all* raw pointers.
MemoryKind::Stack => (state.base_ptr_tag(id, machine), Permission::Unique), MemoryKind::Stack => (state.root_ptr_tag(id, machine), Permission::Unique),
// Everything else is shared by default. // Everything else is shared by default.
_ => (state.base_ptr_tag(id, machine), Permission::SharedReadWrite), _ => (state.root_ptr_tag(id, machine), Permission::SharedReadWrite),
}; };
Stacks::new(size, perm, base_tag, id, machine) Stacks::new(size, perm, base_tag, id, machine)
} }

View file

@ -47,7 +47,7 @@ impl Stack {
let mut first_removed = None; let mut first_removed = None;
// We never consider removing the bottom-most tag. For stacks without an unknown // We never consider removing the bottom-most tag. For stacks without an unknown
// bottom this preserves the base tag. // bottom this preserves the root tag.
// Note that the algorithm below is based on considering the tag at read_idx - 1, // Note that the algorithm below is based on considering the tag at read_idx - 1,
// so precisely considering the tag at index 0 for removal when we have an unknown // so precisely considering the tag at index 0 for removal when we have an unknown
// bottom would complicate the implementation. The simplification of not considering // bottom would complicate the implementation. The simplification of not considering
@ -93,7 +93,7 @@ impl Stack {
self.unique_range = 0..self.len(); self.unique_range = 0..self.len();
} }
// Replace any Items which have been collected with the base item, a known-good value. // Replace any Items which have been collected with the root item, a known-good value.
for i in 0..CACHE_LEN { for i in 0..CACHE_LEN {
if self.cache.idx[i] >= first_removed { if self.cache.idx[i] >= first_removed {
self.cache.items[i] = self.borrows[0]; self.cache.items[i] = self.borrows[0];
@ -331,7 +331,7 @@ impl<'tcx> Stack {
self.verify_cache_consistency(); self.verify_cache_consistency();
} }
/// Construct a new `Stack` using the passed `Item` as the base tag. /// Construct a new `Stack` using the passed `Item` as the root tag.
pub fn new(item: Item) -> Self { pub fn new(item: Item) -> Self {
Stack { Stack {
borrows: vec![item], borrows: vec![item],
@ -438,8 +438,8 @@ impl<'tcx> Stack {
let mut removed = 0; let mut removed = 0;
let mut cursor = 0; let mut cursor = 0;
// Remove invalid entries from the cache by rotating them to the end of the cache, then // Remove invalid entries from the cache by rotating them to the end of the cache, then
// keep track of how many invalid elements there are and overwrite them with the base tag. // keep track of how many invalid elements there are and overwrite them with the root tag.
// The base tag here serves as a harmless default value. // The root tag here serves as a harmless default value.
for _ in 0..CACHE_LEN - 1 { for _ in 0..CACHE_LEN - 1 {
if self.cache.idx[cursor] >= start { if self.cache.idx[cursor] >= start {
self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1); self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1);

View file

@ -37,7 +37,7 @@ impl<'tcx> Tree {
_kind: MemoryKind, _kind: MemoryKind,
machine: &MiriMachine<'_, 'tcx>, machine: &MiriMachine<'_, 'tcx>,
) -> Self { ) -> Self {
let tag = state.base_ptr_tag(id, machine); // Fresh tag for the root let tag = state.root_ptr_tag(id, machine); // Fresh tag for the root
let span = machine.current_span(); let span = machine.current_span();
Tree::new(tag, size, span) Tree::new(tag, size, span)
} }

View file

@ -503,7 +503,7 @@ pub struct MiriMachine<'mir, 'tcx> {
/// Crates which are considered local for the purposes of error reporting. /// Crates which are considered local for the purposes of error reporting.
pub(crate) local_crates: Vec<CrateNum>, pub(crate) local_crates: Vec<CrateNum>,
/// Mapping extern static names to their base pointer. /// Mapping extern static names to their pointer.
extern_statics: FxHashMap<Symbol, Pointer<Provenance>>, extern_statics: FxHashMap<Symbol, Pointer<Provenance>>,
/// The random number generator used for resolving non-determinism. /// The random number generator used for resolving non-determinism.
@ -1042,14 +1042,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
ecx.generate_nan(inputs) ecx.generate_nan(inputs)
} }
fn thread_local_static_base_pointer( fn thread_local_static_pointer(
ecx: &mut MiriInterpCx<'mir, 'tcx>, ecx: &mut MiriInterpCx<'mir, 'tcx>,
def_id: DefId, def_id: DefId,
) -> InterpResult<'tcx, Pointer<Provenance>> { ) -> InterpResult<'tcx, Pointer<Provenance>> {
ecx.get_or_create_thread_local_alloc(def_id) ecx.get_or_create_thread_local_alloc(def_id)
} }
fn extern_static_base_pointer( fn extern_static_pointer(
ecx: &MiriInterpCx<'mir, 'tcx>, ecx: &MiriInterpCx<'mir, 'tcx>,
def_id: DefId, def_id: DefId,
) -> InterpResult<'tcx, Pointer<Provenance>> { ) -> InterpResult<'tcx, Pointer<Provenance>> {
@ -1090,7 +1090,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
alloc: Cow<'b, Allocation>, alloc: Cow<'b, Allocation>,
kind: Option<MemoryKind>, kind: Option<MemoryKind>,
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>> { ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>> {
let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None");
if ecx.machine.tracked_alloc_ids.contains(&id) { if ecx.machine.tracked_alloc_ids.contains(&id) {
ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc( ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(
id, id,
@ -1135,7 +1135,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
weak_memory: buffer_alloc, weak_memory: buffer_alloc,
backtrace, backtrace,
}, },
|ptr| ecx.global_base_pointer(ptr), |ptr| ecx.global_root_pointer(ptr),
)?; )?;
if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) { if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) {
@ -1148,31 +1148,33 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
Ok(Cow::Owned(alloc)) Ok(Cow::Owned(alloc))
} }
fn adjust_alloc_base_pointer( fn adjust_alloc_root_pointer(
ecx: &MiriInterpCx<'mir, 'tcx>, ecx: &MiriInterpCx<'mir, 'tcx>,
ptr: Pointer<CtfeProvenance>, ptr: Pointer<CtfeProvenance>,
kind: Option<MemoryKind>,
) -> InterpResult<'tcx, Pointer<Provenance>> { ) -> InterpResult<'tcx, Pointer<Provenance>> {
let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None");
let alloc_id = ptr.provenance.alloc_id(); let alloc_id = ptr.provenance.alloc_id();
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
// The machine promises to never call us on thread-local or extern statics. // The machine promises to never call us on thread-local or extern statics.
match ecx.tcx.try_get_global_alloc(alloc_id) { match ecx.tcx.try_get_global_alloc(alloc_id) {
Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => {
panic!("adjust_alloc_base_pointer called on thread-local static") panic!("adjust_alloc_root_pointer called on thread-local static")
} }
Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => {
panic!("adjust_alloc_base_pointer called on extern static") panic!("adjust_alloc_root_pointer called on extern static")
} }
_ => {} _ => {}
} }
} }
// FIXME: can we somehow preserve the immutability of `ptr`? // FIXME: can we somehow preserve the immutability of `ptr`?
let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker { let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
borrow_tracker.borrow_mut().base_ptr_tag(alloc_id, &ecx.machine) borrow_tracker.borrow_mut().root_ptr_tag(alloc_id, &ecx.machine)
} else { } else {
// Value does not matter, SB is disabled // Value does not matter, SB is disabled
BorTag::default() BorTag::default()
}; };
ecx.ptr_from_rel_ptr(ptr, tag) ecx.adjust_alloc_root_pointer(ptr, tag, kind)
} }
/// Called on `usize as ptr` casts. /// Called on `usize as ptr` casts.

View file

@ -6,7 +6,7 @@ LL | unsafe { *x = 0 };
| |
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <TAG> was created here, as the base tag for ALLOC help: <TAG> was created here, as the root tag for ALLOC
--> $DIR/invalidate_against_protector3.rs:LL:CC --> $DIR/invalidate_against_protector3.rs:LL:CC
| |
LL | let ptr = alloc(Layout::for_value(&0i32)) as *mut i32; LL | let ptr = alloc(Layout::for_value(&0i32)) as *mut i32;

View file

@ -0,0 +1 @@
// Empty

View file

@ -0,0 +1,31 @@
#![feature(rustc_private)]
#[cfg(unix)]
extern crate libc;
extern crate run_make_support;
use run_make_support::{aux_build, tmp_dir};
use std::fs;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
fn main() {
#[cfg(unix)]
unsafe {
libc::umask(0o002);
}
aux_build().arg("foo.rs").run();
verify(&tmp_dir().join("libfoo.rlib"));
}
fn verify(path: &Path) {
let perm = fs::metadata(path).unwrap().permissions();
assert!(!perm.readonly());
// Check that the file is readable for everyone
#[cfg(unix)]
assert_eq!(perm.mode(), 0o100664);
}

View file

@ -1,13 +1,9 @@
//@ run-pass //@ run-pass
//@ pretty-expanded FIXME #23616 //@ pretty-expanded FIXME #23616
#![feature(rustc_private)]
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")] #[link(name = "rust_test_helpers", kind = "static")]
extern "C" { extern "C" {
fn rust_get_test_int() -> libc::intptr_t; fn rust_get_test_int() -> isize;
} }
pub fn main() { pub fn main() {

View file

@ -1,14 +1,10 @@
//@ run-pass //@ run-pass
//@ pretty-expanded FIXME #23616 //@ pretty-expanded FIXME #23616
#![feature(rustc_private)]
mod rustrt { mod rustrt {
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")] #[link(name = "rust_test_helpers", kind = "static")]
extern "C" { extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t; pub fn rust_get_test_int() -> isize;
} }
} }

View file

@ -1,9 +1,6 @@
#![crate_name = "anonexternmod"] #![crate_name = "anonexternmod"]
#![feature(rustc_private)]
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")] #[link(name = "rust_test_helpers", kind = "static")]
extern "C" { extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t; pub fn rust_get_test_int() -> isize;
} }

View file

@ -1,28 +1,28 @@
#![crate_name = "foreign_lib"] #![crate_name = "foreign_lib"]
#![feature(rustc_private)]
pub mod rustrt { pub mod rustrt {
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")] #[link(name = "rust_test_helpers", kind = "static")]
extern "C" { extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t; pub fn rust_get_test_int() -> isize;
} }
} }
pub mod rustrt2 { pub mod rustrt2 {
extern crate libc;
extern "C" { extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t; pub fn rust_get_test_int() -> isize;
} }
} }
pub mod rustrt3 { pub mod rustrt3 {
// Different type, but same ABI (on all supported platforms). // The point of this test is to ensure that we don't ICE or trigger LLVM asserts when importing
// Ensures that we don't ICE or trigger LLVM asserts when // the same symbol with different types. This is not really possible to test portably; there is
// importing the same symbol under different types. // no different signature we can come up with that is different to LLVM but which for sure has
// See https://github.com/rust-lang/rust/issues/32740. // the same behavior on all platforms. The signed-ness of integers is ignored by LLVM as well
// as pointee types. So the only ways to make our signatures differ are to use
// differently-sized integers which is definitely an ABI mismatch, or to rely on pointers and
// isize/usize having the same ABI, which is wrong on CHERI and probably other niche platforms.
// If this test causes you trouble, please file an issue.
// See https://github.com/rust-lang/rust/issues/32740 for the bug that prompted this test.
extern "C" { extern "C" {
pub fn rust_get_test_int() -> *const u8; pub fn rust_get_test_int() -> *const u8;
} }
@ -32,6 +32,6 @@ pub fn local_uses() {
unsafe { unsafe {
let x = rustrt::rust_get_test_int(); let x = rustrt::rust_get_test_int();
assert_eq!(x, rustrt2::rust_get_test_int()); assert_eq!(x, rustrt2::rust_get_test_int());
assert_eq!(x as *const _, rustrt3::rust_get_test_int()); assert_eq!(x as *const u8, rustrt3::rust_get_test_int());
} }
} }

View file

@ -4,13 +4,12 @@
// Check that we can still call duplicated extern (imported) functions // Check that we can still call duplicated extern (imported) functions
// which were declared in another crate. See issues #32740 and #32783. // which were declared in another crate. See issues #32740 and #32783.
extern crate foreign_lib; extern crate foreign_lib;
pub fn main() { pub fn main() {
unsafe { unsafe {
let x = foreign_lib::rustrt::rust_get_test_int(); let x = foreign_lib::rustrt::rust_get_test_int();
assert_eq!(x, foreign_lib::rustrt2::rust_get_test_int()); assert_eq!(x, foreign_lib::rustrt2::rust_get_test_int());
assert_eq!(x as *const _, foreign_lib::rustrt3::rust_get_test_int()); assert_eq!(x as *const u8, foreign_lib::rustrt3::rust_get_test_int());
} }
} }

View file

@ -1,21 +0,0 @@
//@ run-pass
// ABI is cdecl by default
//@ pretty-expanded FIXME #23616
#![feature(rustc_private)]
mod rustrt {
extern crate libc;
#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t;
}
}
pub fn main() {
unsafe {
rustrt::rust_get_test_int();
}
}

View file

@ -148,7 +148,7 @@ mod test_foreign_items {
#![rustc_dummy] #![rustc_dummy]
#[rustc_dummy] #[rustc_dummy]
fn rust_get_test_int() -> u32; fn rust_get_test_int() -> isize;
} }
} }
} }

View file

@ -2,13 +2,10 @@
#![allow(unused_attributes)] #![allow(unused_attributes)]
#![allow(dead_code)] #![allow(dead_code)]
//@ pretty-expanded FIXME #23616 //@ pretty-expanded FIXME #23616
#![feature(rustc_private)]
mod rustrt { mod rustrt {
extern crate libc;
extern "C" { extern "C" {
pub fn rust_get_test_int() -> libc::intptr_t; pub fn rust_get_test_int() -> isize;
} }
} }

View file

@ -0,0 +1,15 @@
// issue: rust-lang/rust#124022
struct Type<T>;
//~^ ERROR type parameter `T` is never used
fn main() {
{
impl<T> Type<T> {
fn new() -> Type<T> {
Type
//~^ ERROR type annotations needed
}
}
};
}

View file

@ -0,0 +1,24 @@
error[E0392]: type parameter `T` is never used
--> $DIR/dont-collect-stmts-from-parent-body.rs:3:13
|
LL | struct Type<T>;
| ^ unused type parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
error[E0282]: type annotations needed
--> $DIR/dont-collect-stmts-from-parent-body.rs:10:17
|
LL | Type
| ^^^^ cannot infer type of the type parameter `T` declared on the struct `Type`
|
help: consider specifying the generic argument
|
LL | Type::<T>
| +++++
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0282, E0392.
For more information about an error, try `rustc --explain E0282`.

View file

@ -256,6 +256,20 @@ fn fake_macros() -> impl std::fmt::Debug {
} }
} }
fn fish_fight() {
trait Rope {
fn _____________<U>(_: Self, _: U) where Self: Sized {}
}
struct T;
impl Rope for T {}
fn tug_o_war(_: impl Fn(T, T)) {}
tug_o_war(<T>::_____________::<T>);
}
pub fn main() { pub fn main() {
strange(); strange();
funny(); funny();
@ -284,4 +298,5 @@ pub fn main() {
infcx(); infcx();
return_already(); return_already();
fake_macros(); fake_macros();
fish_fight();
} }

View file

@ -417,6 +417,54 @@ message_on_remove = "Issue #{number}'s prioritization request has been removed."
message_on_close = "Issue #{number} has been closed while requested for prioritization." message_on_close = "Issue #{number} has been closed while requested for prioritization."
message_on_reopen = "Issue #{number} has been reopened." message_on_reopen = "Issue #{number} has been reopened."
# FIXME: Patch triagebot to support `notify-zulip.<label>` getting mapped to an array of actions.
# At the moment, the beta-nominated+T-rustdoc action fully occupies the beta-nominated slot
# preventing others from adding more beta-nominated actions.
[notify-zulip."beta-nominated"]
required_labels = ["T-rustdoc"]
zulip_stream = 266220 # #t-rustdoc
topic = "beta-nominated: #{number}"
# Zulip polls may not be preceded by any other text and pings & short links inside
# the title of a poll don't get recognized. Therefore we need to send two messages.
message_on_add = [
"""\
@*T-rustdoc* PR #{number} "{title}" has been nominated for beta backport.
""",
"""\
/poll Approve beta backport of #{number}?
approve
decline
don't know
""",
]
message_on_remove = "PR #{number}'s beta-nomination has been removed."
message_on_close = "PR #{number} has been closed. Thanks for participating!"
message_on_reopen = "PR #{number} has been reopened. Pinging @*T-rustdoc*."
# FIXME: Patch triagebot to support `notify-zulip.<label>` getting mapped to an array of actions.
# At the moment, the stable-nominated+T-rustdoc action fully occupies the stable-nominated slot
# preventing others from adding more stable-nominated actions.
[notify-zulip."stable-nominated"]
required_labels = ["T-rustdoc"]
zulip_stream = 266220 # #t-rustdoc
topic = "stable-nominated: #{number}"
# Zulip polls may not be preceded by any other text and pings & short links inside
# the title of a poll don't get recognized. Therefore we need to send two messages.
message_on_add = [
"""\
@*T-rustdoc* PR #{number} "{title}" has been nominated for stable backport.
""",
"""\
/poll Approve stable backport of #{number}?
approve
decline
don't know
""",
]
message_on_remove = "PR #{number}'s stable-nomination has been removed."
message_on_close = "PR #{number} has been closed. Thanks for participating!"
message_on_reopen = "PR #{number} has been reopened. Pinging @*T-rustdoc*."
[notify-zulip."I-types-nominated"] [notify-zulip."I-types-nominated"]
zulip_stream = 326866 # #T-types/nominated zulip_stream = 326866 # #T-types/nominated
topic = "#{number}: {title}" topic = "#{number}: {title}"