Skip to content

Commit

Permalink
Auto merge of #133978 - matthiaskrgr:rollup-6gh1iho, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 7 pull requests

Successful merges:

 - #130209 (Stabilize `std::io::ErrorKind::CrossesDevices`)
 - #130254 (Stabilize `std::io::ErrorKind::QuotaExceeded`)
 - #132187 (Add Extend impls for tuples of arity 1 through 12)
 - #133875 (handle `--json-output` properly)
 - #133934 (Do not implement unsafe auto traits for types with unsafe fields)
 - #133954 (Hide errors whose suggestions would contain error constants or types)
 - #133960 (rustdoc: remove eq for clean::Attributes)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Dec 7, 2024
2 parents cdb89d6 + d210b91 commit 9c707a8
Show file tree
Hide file tree
Showing 32 changed files with 290 additions and 231 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.lower_const_arg(ct, FeedConstTy::No).into()
}
};
if term.references_error() {
continue;
}
// FIXME(#97583): This isn't syntactically well-formed!
where_bounds.push(format!(
" T: {trait}::{assoc_name} = {term}",
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.trait_def(trait_def_id).implement_via_object
}

fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool {
self.trait_def(trait_def_id).safety == hir::Safety::Unsafe
}

fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
self.is_impl_trait_in_trait(def_id)
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,14 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
self.async_destructor_ty(interner)
}

fn has_unsafe_fields(self) -> bool {
if let ty::Adt(adt_def, ..) = self.kind() {
adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe)
} else {
false
}
}
}

/// Type utilities
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_mir_build/src/thir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use rustc_ast as ast;
use rustc_hir::LangItem;
use rustc_middle::bug;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{self, ScalarInt, TyCtxt};
use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _};
use tracing::trace;

use crate::build::parse_float_into_scalar;
Expand All @@ -13,6 +13,10 @@ pub(crate) fn lit_to_const<'tcx>(
) -> Result<ty::Const<'tcx>, LitToConstError> {
let LitToConstInput { lit, ty, neg } = lit_input;

if let Err(guar) = ty.error_reported() {
return Ok(ty::Const::new_error(tcx, guar));
}

let trunc = |n| {
let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
Ok(layout) => layout.size,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ where
return result;
}

// Only consider auto impls of unsafe traits when there are no unsafe
// fields.
if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
&& goal.predicate.self_ty().has_unsafe_fields()
{
return Err(NoSolution);
}

// We only look into opaque types during analysis for opaque types
// outside of their defining scope. Doing so for opaques in the
// defining scope may require calling `typeck` on the same item we're
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use rustc_infer::traits::{
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
use rustc_middle::{bug, span_bug};
use rustc_type_ir::Interner;
use tracing::{debug, instrument, trace};

use super::SelectionCandidate::*;
Expand Down Expand Up @@ -794,6 +795,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Never
| ty::Tuple(_)
| ty::CoroutineWitness(..) => {
use rustc_type_ir::inherent::*;

// Only consider auto impls of unsafe traits when there are
// no unsafe fields.
if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() {
return;
}

// Only consider auto impls if there are no manual impls for the root of `self_ty`.
//
// For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_type_ir/src/inherent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ pub trait Ty<I: Interner<Ty = Self>>:
matches!(self.kind(), ty::FnPtr(..))
}

/// Checks whether this type is an ADT that has unsafe fields.
fn has_unsafe_fields(self) -> bool;

fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
match self.kind() {
ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr),
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ pub trait Interner:

fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;

/// Returns `true` if this is an `unsafe trait`.
fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool;

fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool;

fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;
Expand Down
239 changes: 129 additions & 110 deletions library/core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,131 +492,150 @@ impl Extend<()> for () {
fn extend_one(&mut self, _item: ()) {}
}

#[stable(feature = "extend_for_tuple", since = "1.56.0")]
impl<A, B, ExtendA, ExtendB> Extend<(A, B)> for (ExtendA, ExtendB)
where
ExtendA: Extend<A>,
ExtendB: Extend<B>,
{
/// Allows to `extend` a tuple of collections that also implement `Extend`.
///
/// See also: [`Iterator::unzip`]
///
/// # Examples
/// ```
/// let mut tuple = (vec![0], vec![1]);
/// tuple.extend([(2, 3), (4, 5), (6, 7)]);
/// assert_eq!(tuple.0, [0, 2, 4, 6]);
/// assert_eq!(tuple.1, [1, 3, 5, 7]);
///
/// // also allows for arbitrarily nested tuples as elements
/// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
/// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
///
/// let (a, (b, c)) = nested_tuple;
/// assert_eq!(a, [1, 4, 7]);
/// assert_eq!(b, [2, 5, 8]);
/// assert_eq!(c, [3, 6, 9]);
/// ```
fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) {
let (a, b) = self;
let iter = into_iter.into_iter();
SpecTupleExtend::extend(iter, a, b);
}
macro_rules! spec_tuple_impl {
( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), ) => {
spec_tuple_impl!($trait_name, $default_fn_name, #[doc(fake_variadic)] #[doc = "This trait is implemented for tuples up to twelve items long. The `impl`s for 1- and 3- through 12-ary tuples were stabilized after 2-tuples, in RUSTC_CURRENT_VERSION."] => ($ty_name, $var_name, $extend_ty_name, $cnt),);
};
( ($ty_name:ident, $var_name:ident, $extend_ty_name: ident, $trait_name:ident, $default_fn_name:ident, $cnt:tt), $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $trait_names:ident, $default_fn_names:ident, $cnts:tt),)*) => {

fn extend_one(&mut self, item: (A, B)) {
self.0.extend_one(item.0);
self.1.extend_one(item.1);
}
spec_tuple_impl!($(($ty_names, $var_names, $extend_ty_names, $trait_names, $default_fn_names, $cnts),)*);
spec_tuple_impl!($trait_name, $default_fn_name, #[doc(hidden)] => ($ty_name, $var_name, $extend_ty_name, $cnt), $(($ty_names, $var_names, $extend_ty_names, $cnts),)*);
};
($trait_name:ident, $default_fn_name:ident, #[$meta:meta] $(#[$doctext:meta])? => $(($ty_names:ident, $var_names:ident, $extend_ty_names:ident, $cnts:tt),)*) => {
#[$meta]
$(#[$doctext])?
#[stable(feature = "extend_for_tuple", since = "1.56.0")]
impl<$($ty_names,)* $($extend_ty_names,)*> Extend<($($ty_names,)*)> for ($($extend_ty_names,)*)
where
$($extend_ty_names: Extend<$ty_names>,)*
{
/// Allows to `extend` a tuple of collections that also implement `Extend`.
///
/// See also: [`Iterator::unzip`]
///
/// # Examples
/// ```
/// // Example given for a 2-tuple, but 1- through 12-tuples are supported
/// let mut tuple = (vec![0], vec![1]);
/// tuple.extend([(2, 3), (4, 5), (6, 7)]);
/// assert_eq!(tuple.0, [0, 2, 4, 6]);
/// assert_eq!(tuple.1, [1, 3, 5, 7]);
///
/// // also allows for arbitrarily nested tuples as elements
/// let mut nested_tuple = (vec![1], (vec![2], vec![3]));
/// nested_tuple.extend([(4, (5, 6)), (7, (8, 9))]);
///
/// let (a, (b, c)) = nested_tuple;
/// assert_eq!(a, [1, 4, 7]);
/// assert_eq!(b, [2, 5, 8]);
/// assert_eq!(c, [3, 6, 9]);
/// ```
fn extend<T: IntoIterator<Item = ($($ty_names,)*)>>(&mut self, into_iter: T) {
let ($($var_names,)*) = self;
let iter = into_iter.into_iter();
$trait_name::extend(iter, $($var_names,)*);
}

fn extend_reserve(&mut self, additional: usize) {
self.0.extend_reserve(additional);
self.1.extend_reserve(additional);
}
fn extend_one(&mut self, item: ($($ty_names,)*)) {
$(self.$cnts.extend_one(item.$cnts);)*
}

unsafe fn extend_one_unchecked(&mut self, item: (A, B)) {
// SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
unsafe {
self.0.extend_one_unchecked(item.0);
self.1.extend_one_unchecked(item.1);
}
}
}
fn extend_reserve(&mut self, additional: usize) {
$(self.$cnts.extend_reserve(additional);)*
}

fn default_extend_tuple<A, B, ExtendA, ExtendB>(
iter: impl Iterator<Item = (A, B)>,
a: &mut ExtendA,
b: &mut ExtendB,
) where
ExtendA: Extend<A>,
ExtendB: Extend<B>,
{
fn extend<'a, A, B>(
a: &'a mut impl Extend<A>,
b: &'a mut impl Extend<B>,
) -> impl FnMut((), (A, B)) + 'a {
move |(), (t, u)| {
a.extend_one(t);
b.extend_one(u);
unsafe fn extend_one_unchecked(&mut self, item: ($($ty_names,)*)) {
// SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`.
unsafe {
$(self.$cnts.extend_one_unchecked(item.$cnts);)*
}
}
}
}

let (lower_bound, _) = iter.size_hint();
if lower_bound > 0 {
a.extend_reserve(lower_bound);
b.extend_reserve(lower_bound);
}
trait $trait_name<$($ty_names),*> {
fn extend(self, $($var_names: &mut $ty_names,)*);
}

iter.fold((), extend(a, b));
}
fn $default_fn_name<$($ty_names,)* $($extend_ty_names,)*>(
iter: impl Iterator<Item = ($($ty_names,)*)>,
$($var_names: &mut $extend_ty_names,)*
) where
$($extend_ty_names: Extend<$ty_names>,)*
{
fn extend<'a, $($ty_names,)*>(
$($var_names: &'a mut impl Extend<$ty_names>,)*
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
#[allow(non_snake_case)]
move |(), ($($extend_ty_names,)*)| {
$($var_names.extend_one($extend_ty_names);)*
}
}

trait SpecTupleExtend<A, B> {
fn extend(self, a: &mut A, b: &mut B);
}
let (lower_bound, _) = iter.size_hint();
if lower_bound > 0 {
$($var_names.extend_reserve(lower_bound);)*
}

impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
where
ExtendA: Extend<A>,
ExtendB: Extend<B>,
Iter: Iterator<Item = (A, B)>,
{
default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
default_extend_tuple(self, a, b);
}
}
iter.fold((), extend($($var_names,)*));
}

impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter
where
ExtendA: Extend<A>,
ExtendB: Extend<B>,
Iter: TrustedLen<Item = (A, B)>,
{
fn extend(self, a: &mut ExtendA, b: &mut ExtendB) {
fn extend<'a, A, B>(
a: &'a mut impl Extend<A>,
b: &'a mut impl Extend<B>,
) -> impl FnMut((), (A, B)) + 'a {
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
// so its `size_hint` is exact.
move |(), (t, u)| unsafe {
a.extend_one_unchecked(t);
b.extend_one_unchecked(u);
impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
where
$($extend_ty_names: Extend<$ty_names>,)*
Iter: Iterator<Item = ($($ty_names,)*)>,
{
default fn extend(self, $($var_names: &mut $extend_ty_names),*) {
$default_fn_name(self, $($var_names),*);
}
}

let (lower_bound, upper_bound) = self.size_hint();
impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
where
$($extend_ty_names: Extend<$ty_names>,)*
Iter: TrustedLen<Item = ($($ty_names,)*)>,
{
fn extend(self, $($var_names: &mut $extend_ty_names,)*) {
fn extend<'a, $($ty_names,)*>(
$($var_names: &'a mut impl Extend<$ty_names>,)*
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
#[allow(non_snake_case)]
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
// so its `size_hint` is exact.
move |(), ($($extend_ty_names,)*)| unsafe {
$($var_names.extend_one_unchecked($extend_ty_names);)*
}
}

if upper_bound.is_none() {
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
default_extend_tuple(self, a, b);
return;
}
let (lower_bound, upper_bound) = self.size_hint();

if lower_bound > 0 {
a.extend_reserve(lower_bound);
b.extend_reserve(lower_bound);
}
if upper_bound.is_none() {
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
$default_fn_name(self, $($var_names,)*);
return;
}

self.fold((), extend(a, b));
if lower_bound > 0 {
$($var_names.extend_reserve(lower_bound);)*
}

self.fold((), extend($($var_names,)*));
}
}

};
}

spec_tuple_impl!(
(L, l, EL, TraitL, default_extend_tuple_l, 11),
(K, k, EK, TraitK, default_extend_tuple_k, 10),
(J, j, EJ, TraitJ, default_extend_tuple_j, 9),
(I, i, EI, TraitI, default_extend_tuple_i, 8),
(H, h, EH, TraitH, default_extend_tuple_h, 7),
(G, g, EG, TraitG, default_extend_tuple_g, 6),
(F, f, EF, TraitF, default_extend_tuple_f, 5),
(E, e, EE, TraitE, default_extend_tuple_e, 4),
(D, d, ED, TraitD, default_extend_tuple_d, 3),
(C, c, EC, TraitC, default_extend_tuple_c, 2),
(B, b, EB, TraitB, default_extend_tuple_b, 1),
(A, a, EA, TraitA, default_extend_tuple_a, 0),
);
13 changes: 13 additions & 0 deletions library/core/tests/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,19 @@ fn test_next_chunk() {
assert_eq!(it.next_chunk::<0>().unwrap(), []);
}

#[test]
fn test_collect_into_tuples() {
let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)];
let b = vec![1, 4, 7];
let c = vec![2, 5, 8];
let d = vec![3, 6, 9];
let mut e = (Vec::new(), Vec::new(), Vec::new());
a.iter().cloned().collect_into(&mut e);
assert!(e.0 == b);
assert!(e.1 == c);
assert!(e.2 == d);
}

// just tests by whether or not this compiles
fn _empty_impl_all_auto_traits<T>() {
use std::panic::{RefUnwindSafe, UnwindSafe};
Expand Down
Loading

0 comments on commit 9c707a8

Please sign in to comment.