Skip to content

Commit

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

Rollup of 9 pull requests

Successful merges:

 - rust-lang#102406 (Make `missing_copy_implementations` more cautious)
 - rust-lang#105265 (Add `rustc_on_unimplemented` to `Sum` and `Product` trait.)
 - rust-lang#105385 (Skip test on s390x as LLD does not support the platform)
 - rust-lang#105453 (Make `VecDeque::from_iter` O(1) from `vec(_deque)::IntoIter`)
 - rust-lang#105468 (Mangle "main" as "__main_void" on wasm32-wasi)
 - rust-lang#105480 (rustdoc: remove no-op mobile CSS `#sidebar-toggle { text-align }`)
 - rust-lang#105489 (Fix typo in apple_base.rs)
 - rust-lang#105504 (rustdoc: make stability badge CSS more consistent)
 - rust-lang#105506 (Tweak `rustc_must_implement_one_of` diagnostic output)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Dec 10, 2022
2 parents 0d5573e + 376b0bc commit a000811
Show file tree
Hide file tree
Showing 21 changed files with 357 additions and 80 deletions.
19 changes: 8 additions & 11 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
.struct_span_err(
attr.span,
"the `#[rustc_must_implement_one_of]` attribute must be \
used with at least 2 args",
used with at least 2 args",
)
.emit();

Expand Down Expand Up @@ -987,7 +987,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
tcx.sess
.struct_span_err(
item.span,
"This function doesn't have a default implementation",
"function doesn't have a default implementation",
)
.span_note(attr_span, "required by this annotation")
.emit();
Expand All @@ -999,17 +999,17 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
}
Some(item) => {
tcx.sess
.struct_span_err(item.span, "Not a function")
.struct_span_err(item.span, "not a function")
.span_note(attr_span, "required by this annotation")
.note(
"All `#[rustc_must_implement_one_of]` arguments \
must be associated function names",
"all `#[rustc_must_implement_one_of]` arguments must be associated \
function names",
)
.emit();
}
None => {
tcx.sess
.struct_span_err(ident.span, "Function not found in this trait")
.struct_span_err(ident.span, "function not found in this trait")
.emit();
}
}
Expand All @@ -1027,11 +1027,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
for ident in &*list {
if let Some(dup) = set.insert(ident.name, ident.span) {
tcx.sess
.struct_span_err(vec![dup, ident.span], "Functions names are duplicated")
.note(
"All `#[rustc_must_implement_one_of]` arguments \
must be unique",
)
.struct_span_err(vec![dup, ident.span], "functions names are duplicated")
.note("all `#[rustc_must_implement_one_of]` arguments must be unique")
.emit();

no_dups = false;
Expand Down
32 changes: 31 additions & 1 deletion compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, InnerSpan, Span};
use rustc_target::abi::{Abi, VariantIdx};
use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
use rustc_trait_selection::traits::{self, misc::can_type_implement_copy, EvaluationResult};

use crate::nonstandard_style::{method_context, MethodLateContext};

Expand Down Expand Up @@ -750,10 +751,39 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
if def.has_dtor(cx.tcx) {
return;
}

// If the type contains a raw pointer, it may represent something like a handle,
// and recommending Copy might be a bad idea.
for field in def.all_fields() {
let did = field.did;
if cx.tcx.type_of(did).is_unsafe_ptr() {
return;
}
}
let param_env = ty::ParamEnv::empty();
if ty.is_copy_modulo_regions(cx.tcx, param_env) {
return;
}

// We shouldn't recommend implementing `Copy` on stateful things,
// such as iterators.
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) {
if cx.tcx.infer_ctxt().build().type_implements_trait(iter_trait, [ty], param_env)
== EvaluationResult::EvaluatedToOk
{
return;
}
}

// Default value of clippy::trivially_copy_pass_by_ref
const MAX_SIZE: u64 = 256;

if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()) {
if size > MAX_SIZE {
return;
}
}

if can_type_implement_copy(
cx.tcx,
param_env,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/apple_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ pub fn macos_llvm_target(arch: Arch) -> String {
fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]> {
// Apple platforms only officially support macOS as a host for any compilation.
//
// If building for macOS, we go ahead and remove any erronous environment state
// If building for macOS, we go ahead and remove any erroneous environment state
// that's only applicable to cross-OS compilation. Always leave anything for the
// host OS alone though.
if os == "macos" {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_target/src/spec/wasm32_wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ pub fn target() -> Target {
// `args::args()` makes the WASI API calls itself.
options.main_needs_argc_argv = false;

// And, WASI mangles the name of "main" to distinguish between different
// signatures.
options.entry_name = "__main_void".into();

Target {
llvm_target: "wasm32-wasi".into(),
pointer_width: 32,
Expand Down
4 changes: 4 additions & 0 deletions library/alloc/src/collections/vec_deque/into_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ impl<T, A: Allocator> IntoIter<T, A> {
pub(super) fn new(inner: VecDeque<T, A>) -> Self {
IntoIter { inner }
}

pub(super) fn into_vecdeque(self) -> VecDeque<T, A> {
self.inner
}
}

#[stable(feature = "collection_debug", since = "1.17.0")]
Expand Down
48 changes: 37 additions & 11 deletions library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ use self::spec_extend::SpecExtend;

mod spec_extend;

use self::spec_from_iter::SpecFromIter;

mod spec_from_iter;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -586,6 +590,38 @@ impl<T, A: Allocator> VecDeque<T, A> {
VecDeque { head: 0, len: 0, buf: RawVec::with_capacity_in(capacity, alloc) }
}

/// Creates a `VecDeque` from a raw allocation, when the initialized
/// part of that allocation forms a *contiguous* subslice thereof.
///
/// For use by `vec::IntoIter::into_vecdeque`
///
/// # Safety
///
/// All the usual requirements on the allocated memory like in
/// `Vec::from_raw_parts_in`, but takes a *range* of elements that are
/// initialized rather than only supporting `0..len`. Requires that
/// `initialized.start` ≤ `initialized.end` ≤ `capacity`.
#[inline]
pub(crate) unsafe fn from_contiguous_raw_parts_in(
ptr: *mut T,
initialized: Range<usize>,
capacity: usize,
alloc: A,
) -> Self {
debug_assert!(initialized.start <= initialized.end);
debug_assert!(initialized.end <= capacity);

// SAFETY: Our safety precondition guarantees the range length won't wrap,
// and that the allocation is valid for use in `RawVec`.
unsafe {
VecDeque {
head: initialized.start,
len: initialized.end.unchecked_sub(initialized.start),
buf: RawVec::from_raw_parts_in(ptr, capacity, alloc),
}
}
}

/// Provides a reference to the element at the given index.
///
/// Element at index 0 is the front of the queue.
Expand Down Expand Up @@ -2699,18 +2735,8 @@ impl<T, A: Allocator> IndexMut<usize> for VecDeque<T, A> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> FromIterator<T> for VecDeque<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> VecDeque<T> {
// Since converting is O(1) now, might as well re-use that logic
// (including things like the `vec::IntoIter`→`Vec` specialization)
// especially as that could save us some monomorphiziation work
// if one uses the same iterators (like slice ones) with both.
return from_iter_via_vec(iter.into_iter());

#[inline]
fn from_iter_via_vec<U>(iter: impl Iterator<Item = U>) -> VecDeque<U> {
Vec::from_iter(iter).into()
}
SpecFromIter::spec_from_iter(iter.into_iter())
}
}

Expand Down
33 changes: 33 additions & 0 deletions library/alloc/src/collections/vec_deque/spec_from_iter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use super::{IntoIter, VecDeque};

/// Specialization trait used for `VecDeque::from_iter`
pub(super) trait SpecFromIter<T, I> {
fn spec_from_iter(iter: I) -> Self;
}

impl<T, I> SpecFromIter<T, I> for VecDeque<T>
where
I: Iterator<Item = T>,
{
default fn spec_from_iter(iterator: I) -> Self {
// Since converting is O(1) now, just re-use the `Vec` logic for
// anything where we can't do something extra-special for `VecDeque`,
// especially as that could save us some monomorphiziation work
// if one uses the same iterators (like slice ones) with both.
crate::vec::Vec::from_iter(iterator).into()
}
}

impl<T> SpecFromIter<T, crate::vec::IntoIter<T>> for VecDeque<T> {
#[inline]
fn spec_from_iter(iterator: crate::vec::IntoIter<T>) -> Self {
iterator.into_vecdeque()
}
}

impl<T> SpecFromIter<T, IntoIter<T>> for VecDeque<T> {
#[inline]
fn spec_from_iter(iterator: IntoIter<T>) -> Self {
iterator.into_vecdeque()
}
}
29 changes: 29 additions & 0 deletions library/alloc/src/vec/into_iter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(not(no_global_oom_handling))]
use super::AsVecIntoIter;
use crate::alloc::{Allocator, Global};
#[cfg(not(no_global_oom_handling))]
use crate::collections::VecDeque;
use crate::raw_vec::RawVec;
use core::array;
use core::fmt;
Expand Down Expand Up @@ -132,6 +134,33 @@ impl<T, A: Allocator> IntoIter<T, A> {
pub(crate) fn forget_remaining_elements(&mut self) {
self.ptr = self.end;
}

#[cfg(not(no_global_oom_handling))]
#[inline]
pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
// Keep our `Drop` impl from dropping the elements and the allocator
let mut this = ManuallyDrop::new(self);

// SAFETY: This allocation originally came from a `Vec`, so it passes
// all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
// so the `sub_ptr`s below cannot wrap, and will produce a well-formed
// range. `end` ≤ `buf + cap`, so the range will be in-bounds.
// Taking `alloc` is ok because nothing else is going to look at it,
// since our `Drop` impl isn't going to run so there's no more code.
unsafe {
let buf = this.buf.as_ptr();
let initialized = if T::IS_ZST {
// All the pointers are the same for ZSTs, so it's fine to
// say that they're all at the beginning of the "allocation".
0..this.len()
} else {
this.ptr.sub_ptr(buf)..this.end.sub_ptr(buf)
};
let cap = this.cap;
let alloc = ManuallyDrop::take(&mut this.alloc);
VecDeque::from_contiguous_raw_parts_in(buf, initialized, cap, alloc)
}
}
}

#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]
Expand Down
36 changes: 36 additions & 0 deletions library/alloc/tests/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1736,3 +1736,39 @@ fn test_resize_keeps_reserved_space_from_item() {
d.resize(1, v);
assert_eq!(d[0].capacity(), 1234);
}

#[test]
fn test_collect_from_into_iter_keeps_allocation() {
let mut v = Vec::with_capacity(13);
v.extend(0..7);
check(v.as_ptr(), v.last().unwrap(), v.into_iter());

let mut v = VecDeque::with_capacity(13);
v.extend(0..7);
check(&v[0], &v[v.len() - 1], v.into_iter());

fn check(buf: *const i32, last: *const i32, mut it: impl Iterator<Item = i32>) {
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(1));

let mut v: VecDeque<i32> = it.collect();
assert_eq!(v.capacity(), 13);
assert_eq!(v.as_slices().0.as_ptr(), buf.wrapping_add(2));
assert_eq!(&v[v.len() - 1] as *const _, last);

assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
v.push_front(7);
assert_eq!(v.as_slices(), ([7, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
v.push_front(8);
assert_eq!(v.as_slices(), ([8, 7, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));

// Now that we've adding thing in place of the two that we removed from
// the front of the iterator, we're back to matching the buffer pointer.
assert_eq!(v.as_slices().0.as_ptr(), buf);
assert_eq!(&v[v.len() - 1] as *const _, last);

v.push_front(9);
assert_eq!(v.as_slices(), ([9].as_slice(), [8, 7, 2, 3, 4, 5, 6].as_slice()));
assert_eq!(v.capacity(), 13);
}
}
8 changes: 8 additions & 0 deletions library/core/src/iter/traits/accum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ use crate::num::Wrapping;
/// [`sum()`]: Iterator::sum
/// [`FromIterator`]: iter::FromIterator
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
#[rustc_on_unimplemented(
message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`",
label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator<Item={A}>`"
)]
pub trait Sum<A = Self>: Sized {
/// Method which takes an iterator and generates `Self` from the elements by
/// "summing up" the items.
Expand All @@ -27,6 +31,10 @@ pub trait Sum<A = Self>: Sized {
/// [`product()`]: Iterator::product
/// [`FromIterator`]: iter::FromIterator
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
#[rustc_on_unimplemented(
message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator",
label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator<Item={A}>`"
)]
pub trait Product<A = Self>: Sized {
/// Method which takes an iterator and generates `Self` from the elements by
/// multiplying the items.
Expand Down
Loading

0 comments on commit a000811

Please sign in to comment.