From 19cb05fd7807e2ea0d7b4f8613eb8b0ad646ce61 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 2 Mar 2024 01:51:58 +0000 Subject: [PATCH 1/8] std::net: adding acceptfilter feature for netbsd/freebsd. similar to linux's ext deferaccept, to filter incoming connections before accept. --- library/std/src/os/freebsd/net.rs | 26 ++++++++++++++++++++++++ library/std/src/os/netbsd/net.rs | 26 ++++++++++++++++++++++++ library/std/src/sys/pal/unix/net.rs | 31 +++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/library/std/src/os/freebsd/net.rs b/library/std/src/os/freebsd/net.rs index 33990d54caae0..b7e0fdc0a9aab 100644 --- a/library/std/src/os/freebsd/net.rs +++ b/library/std/src/os/freebsd/net.rs @@ -2,6 +2,7 @@ #![unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +use crate::ffi::CStr; use crate::io; use crate::os::unix::net; use crate::sealed::Sealed; @@ -40,6 +41,15 @@ pub trait UnixSocketExt: Sealed { /// ``` #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()>; + + /// Get a filter name if one had been set previously on the socket. + #[unstable(feature = "acceptfilter", issue = "121891")] + fn acceptfilter(&self) -> io::Result<&CStr>; + + /// Set or disable a filter on the socket to filter incoming connections + /// to defer it before accept(2) + #[unstable(feature = "acceptfilter", issue = "121891")] + fn set_acceptfilter(&self, name: &CStr) -> io::Result<()>; } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -51,6 +61,14 @@ impl UnixSocketExt for net::UnixDatagram { fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> { self.as_inner().set_local_creds_persistent(local_creds_persistent) } + + fn acceptfilter(&self) -> io::Result<&CStr> { + self.as_inner().acceptfilter() + } + + fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> { + self.as_inner().set_acceptfilter(name) + } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -62,4 +80,12 @@ impl UnixSocketExt for net::UnixStream { fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> { self.as_inner().set_local_creds_persistent(local_creds_persistent) } + + fn acceptfilter(&self) -> io::Result<&CStr> { + self.as_inner().acceptfilter() + } + + fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> { + self.as_inner().set_acceptfilter(name) + } } diff --git a/library/std/src/os/netbsd/net.rs b/library/std/src/os/netbsd/net.rs index 5c82f43077d4c..b9679c7b3af33 100644 --- a/library/std/src/os/netbsd/net.rs +++ b/library/std/src/os/netbsd/net.rs @@ -2,6 +2,7 @@ #![unstable(feature = "unix_socket_ancillary_data", issue = "76915")] +use crate::ffi::CStr; use crate::io; use crate::os::unix::net; use crate::sealed::Sealed; @@ -40,6 +41,15 @@ pub trait UnixSocketExt: Sealed { /// ``` #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] fn set_local_creds(&self, local_creds: bool) -> io::Result<()>; + + /// Get a filter name if one had been set previously on the socket. + #[unstable(feature = "acceptfilter", issue = "121891")] + fn acceptfilter(&self) -> io::Result<&CStr>; + + /// Set or disable a filter on the socket to filter incoming connections + /// to defer it before accept(2) + #[unstable(feature = "acceptfilter", issue = "121891")] + fn set_acceptfilter(&self, name: &CStr) -> io::Result<()>; } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -51,6 +61,14 @@ impl UnixSocketExt for net::UnixDatagram { fn set_local_creds(&self, local_creds: bool) -> io::Result<()> { self.as_inner().set_local_creds(local_creds) } + + fn acceptfilter(&self) -> io::Result<&CStr> { + self.as_inner().acceptfilter() + } + + fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> { + self.as_inner().set_acceptfilter(name) + } } #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] @@ -62,4 +80,12 @@ impl UnixSocketExt for net::UnixStream { fn set_local_creds(&self, local_creds: bool) -> io::Result<()> { self.as_inner().set_local_creds(local_creds) } + + fn acceptfilter(&self) -> io::Result<&CStr> { + self.as_inner().acceptfilter() + } + + fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> { + self.as_inner().set_acceptfilter(name) + } } diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 09750b6ffc897..1f140f7844f7c 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -453,6 +453,37 @@ impl Socket { Ok(raw as u32) } + #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] + pub fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> { + if !name.to_bytes().is_empty() { + const AF_NAME_MAX: usize = 16; + let mut buf = [0; AF_NAME_MAX]; + for (src, dst) in name.to_bytes().iter().zip(&mut buf[..AF_NAME_MAX - 1]) { + *dst = *src as i8; + } + let mut arg: libc::accept_filter_arg = unsafe { mem::zeroed() }; + arg.af_name = buf; + setsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER, &mut arg) + } else { + setsockopt( + self, + libc::SOL_SOCKET, + libc::SO_ACCEPTFILTER, + core::ptr::null_mut() as *mut c_void, + ) + } + } + + #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] + pub fn acceptfilter(&self) -> io::Result<&CStr> { + let arg: libc::accept_filter_arg = + getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)?; + let s: &[u8] = + unsafe { core::slice::from_raw_parts(arg.af_name.as_ptr() as *const u8, 16) }; + let name = CStr::from_bytes_with_nul(s).unwrap(); + Ok(name) + } + #[cfg(any(target_os = "android", target_os = "linux",))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) From f6f89dc2023315b777f0ffef3b4c4573d364beb8 Mon Sep 17 00:00:00 2001 From: ultrabear Date: Thu, 21 Mar 2024 00:54:50 -0700 Subject: [PATCH 2/8] BTree(Set|Map): Guarantee that `IntoIter` will iterate in sorted by key order --- library/alloc/src/collections/btree/map.rs | 3 ++- library/alloc/src/collections/btree/set.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index e99c6220e2064..66b45f866017b 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -415,7 +415,7 @@ impl<'a, K: 'a, V: 'a> Default for IterMut<'a, K, V> { } } -/// An owning iterator over the entries of a `BTreeMap`. +/// An owning iterator over the entries of a `BTreeMap`, sorted by key. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] /// (provided by the [`IntoIterator`] trait). See its documentation for more. @@ -1632,6 +1632,7 @@ impl<'a, K, V> IterMut<'a, K, V> { } } +/// Gets an owning iterator over the entries of the map, sorted by key. #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { type Item = (K, V); diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index ed91ae1a66e3d..9c0b89188d8c5 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -140,7 +140,7 @@ impl fmt::Debug for Iter<'_, T> { } } -/// An owning iterator over the items of a `BTreeSet`. +/// An owning iterator over the items of a `BTreeSet` in ascending order. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] /// (provided by the [`IntoIterator`] trait). See its documentation for more. @@ -1232,6 +1232,7 @@ impl From<[T; N]> for BTreeSet { } } +/// Gets an owning iterator over the elements of the `BTreeSet` in ascending order. #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeSet { type Item = T; From f8a093c8ea456cb64966da2983eb988e74700fde Mon Sep 17 00:00:00 2001 From: ultrabear Date: Thu, 21 Mar 2024 02:05:11 -0700 Subject: [PATCH 3/8] document iteration ordering on into_iter method instead of IntoIterator implementation --- library/alloc/src/collections/btree/map.rs | 2 +- library/alloc/src/collections/btree/set.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 66b45f866017b..53b25a9ef25f8 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1632,12 +1632,12 @@ impl<'a, K, V> IterMut<'a, K, V> { } } -/// Gets an owning iterator over the entries of the map, sorted by key. #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { type Item = (K, V); type IntoIter = IntoIter; + /// Gets an owning iterator over the entries of the map, sorted by key. fn into_iter(self) -> IntoIter { let mut me = ManuallyDrop::new(self); if let Some(root) = me.root.take() { diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 9c0b89188d8c5..a110ee9c7f36c 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1232,13 +1232,12 @@ impl From<[T; N]> for BTreeSet { } } -/// Gets an owning iterator over the elements of the `BTreeSet` in ascending order. #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeSet { type Item = T; type IntoIter = IntoIter; - /// Gets an iterator for moving out the `BTreeSet`'s contents. + /// Gets an iterator for moving out the `BTreeSet`'s contents in ascending order. /// /// # Examples /// From beb0c22c096c68fd853cf65bb44408cf0d5ac99a Mon Sep 17 00:00:00 2001 From: ultrabear Date: Thu, 21 Mar 2024 02:07:46 -0700 Subject: [PATCH 4/8] document into_iter in top level docs iterator ordering guarantees --- library/alloc/src/collections/btree/map.rs | 2 +- library/alloc/src/collections/btree/set.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 53b25a9ef25f8..3875f61efafdf 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -72,7 +72,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// `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 +/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::into_iter`], [`BTreeMap::values`], or /// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and /// amortized constant time per item returned. /// diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index a110ee9c7f36c..7508ae468ae5b 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -27,7 +27,7 @@ use crate::alloc::{Allocator, Global}; /// `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 +/// Iterators returned by [`BTreeSet::iter`] and [`BTreeSet::into_iter`] produce their items in order, and take worst-case /// logarithmic and amortized constant time per item returned. /// /// [`Cell`]: core::cell::Cell From 796105ef63acdacd9407a7d22f34af18438801e7 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 21 Mar 2024 19:48:18 +0300 Subject: [PATCH 5/8] make failure logs less verbose Signed-off-by: onur-ozkan --- src/bootstrap/src/lib.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 64bb7bf01f796..e94a767a194a2 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1009,15 +1009,23 @@ impl Build { let result = if !output.status.success() { if print_error { println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n\ - stdout ----\n{}\n\ - stderr ----\n{}\n\n", - command.command, + "\n\nCommand did not execute successfully.\ + \nExpected success, got: {}", output.status, - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) ); + + if !self.is_verbose() { + println!("Add `-v` to see more details.\n"); + } + + self.verbose(|| { + println!( + "\nSTDOUT ----\n{}\n\ + STDERR ----\n{}\n", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ) + }); } Err(()) } else { From ae4c5c891ec55e2bf78615650daded9124552ca0 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 22 Mar 2024 00:48:36 +0900 Subject: [PATCH 6/8] Implement `FusedIterator` for `gen` block --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_span/src/symbol.rs | 2 ++ .../src/solve/assembly/mod.rs | 9 +++++ .../src/solve/normalizes_to/mod.rs | 7 ++++ .../src/solve/trait_goals.rs | 22 +++++++++++++ .../src/traits/select/candidate_assembly.rs | 33 +++++++++++++++---- .../src/traits/select/confirmation.rs | 2 ++ .../src/traits/select/mod.rs | 14 ++++++++ library/core/src/iter/traits/marker.rs | 1 + tests/ui/coroutine/gen_block_is_fused_iter.rs | 21 ++++++++++++ 10 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 tests/ui/coroutine/gen_block_is_fused_iter.rs diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 5118bf5c3b7ab..dbf86f5cf747d 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -214,6 +214,7 @@ language_item_table! { FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); + FusedIterator, sym::fused_iterator, fused_iterator_trait, Target::Trait, GenericRequirement::Exact(0); Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b911a41a112f..c28c577d78014 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -207,6 +207,7 @@ symbols! { FromResidual, FsOpenOptions, FsPermissions, + FusedIterator, Future, FutureOutput, GlobalAlloc, @@ -885,6 +886,7 @@ symbols! { fsub_algebraic, fsub_fast, fundamental, + fused_iterator, future, future_trait, gdb_script_file, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 9f33dce2a6dfe..d92bae2528fbc 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -215,6 +215,13 @@ pub(super) trait GoalKind<'tcx>: goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + /// A coroutine (that comes from a `gen` desugaring) is known to implement + /// `FusedIterator` + fn consider_builtin_fused_iterator_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -497,6 +504,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_future_candidate(self, goal) } else if lang_items.iterator_trait() == Some(trait_def_id) { G::consider_builtin_iterator_candidate(self, goal) + } else if lang_items.fused_iterator_trait() == Some(trait_def_id) { + G::consider_builtin_fused_iterator_candidate(self, goal) } else if lang_items.async_iterator_trait() == Some(trait_def_id) { G::consider_builtin_async_iterator_candidate(self, goal) } else if lang_items.coroutine_trait() == Some(trait_def_id) { diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 85bb6338daff9..6668889323512 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -647,6 +647,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) } + fn consider_builtin_fused_iterator_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`FusedIterator` does not have an associated type: {:?}", goal); + } + fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index c252ad76dfe1d..184ba31f19d20 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -456,6 +456,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + fn consider_builtin_fused_iterator_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + + let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + return Err(NoSolution); + }; + + // Coroutines are not iterators unless they come from `gen` desugaring + let tcx = ecx.tcx(); + if !tcx.coroutine_is_gen(def_id) { + return Err(NoSolution); + } + + // Gen coroutines unconditionally implement `FusedIterator` + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 49091e53be713..9fb4577fb2169 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -118,6 +118,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_future_candidates(obligation, &mut candidates); } else if lang_items.iterator_trait() == Some(def_id) { self.assemble_iterator_candidates(obligation, &mut candidates); + } else if lang_items.fused_iterator_trait() == Some(def_id) { + self.assemble_fused_iterator_candidates(obligation, &mut candidates); } else if lang_items.async_iterator_trait() == Some(def_id) { self.assemble_async_iterator_candidates(obligation, &mut candidates); } else if lang_items.async_fn_kind_helper() == Some(def_id) { @@ -302,14 +304,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { let self_ty = obligation.self_ty().skip_binder(); - if let ty::Coroutine(did, ..) = self_ty.kind() { - // gen constructs get lowered to a special kind of coroutine that - // should directly `impl Iterator`. - if self.tcx().coroutine_is_gen(*did) { - debug!(?self_ty, ?obligation, "assemble_iterator_candidates",); + // gen constructs get lowered to a special kind of coroutine that + // should directly `impl Iterator`. + if let ty::Coroutine(did, ..) = self_ty.kind() + && self.tcx().coroutine_is_gen(*did) + { + debug!(?self_ty, ?obligation, "assemble_iterator_candidates",); - candidates.vec.push(IteratorCandidate); - } + candidates.vec.push(IteratorCandidate); + } + } + + fn assemble_fused_iterator_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = obligation.self_ty().skip_binder(); + // gen constructs get lowered to a special kind of coroutine that + // should directly `impl FusedIterator`. + if let ty::Coroutine(did, ..) = self_ty.kind() + && self.tcx().coroutine_is_gen(*did) + { + debug!(?self_ty, ?obligation, "assemble_fused_iterator_candidates",); + + candidates.vec.push(BuiltinCandidate { has_nested: false }); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 51fc223a5d1b3..aeac2ad77d70f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -267,6 +267,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.copy_clone_conditions(obligation) } else if Some(trait_def) == lang_items.clone_trait() { self.copy_clone_conditions(obligation) + } else if Some(trait_def) == lang_items.fused_iterator_trait() { + self.fused_iterator_conditions(obligation) } else { bug!("unexpected builtin trait {:?}", trait_def) }; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 53aadfb8a44d8..adbc7d12a648d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2259,6 +2259,20 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } + fn fused_iterator_conditions( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> BuiltinImplConditions<'tcx> { + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + if let ty::Coroutine(did, ..) = *self_ty.kind() + && self.tcx().coroutine_is_gen(did) + { + BuiltinImplConditions::Where(ty::Binder::dummy(Vec::new())) + } else { + BuiltinImplConditions::None + } + } + /// For default impls, we need to break apart a type into its /// "constituent types" -- meaning, the types that it contains. /// diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index 8bdbca120d7f9..ad4d63d83b5be 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -28,6 +28,7 @@ pub unsafe trait TrustedFused {} #[rustc_unsafe_specialization_marker] // FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused // but that ICEs iter::Fuse specializations. +#[cfg_attr(not(bootstrap), lang = "fused_iterator")] pub trait FusedIterator: Iterator {} #[stable(feature = "fused", since = "1.26.0")] diff --git a/tests/ui/coroutine/gen_block_is_fused_iter.rs b/tests/ui/coroutine/gen_block_is_fused_iter.rs new file mode 100644 index 0000000000000..f3e19a7f54f03 --- /dev/null +++ b/tests/ui/coroutine/gen_block_is_fused_iter.rs @@ -0,0 +1,21 @@ +//@ revisions: next old +//@compile-flags: --edition 2024 -Zunstable-options +//@[next] compile-flags: -Znext-solver +//@ check-pass +#![feature(gen_blocks)] + +use std::iter::FusedIterator; + +fn foo() -> impl FusedIterator { + gen { yield 42 } +} + +fn bar() -> impl FusedIterator { + gen { yield 42 } +} + +fn baz() -> impl FusedIterator + Iterator { + gen { yield 42 } +} + +fn main() {} From daa65539ce2d1fe51bc92af4607d33c5916f70fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 21 Mar 2024 20:31:31 +0100 Subject: [PATCH 7/8] add test for #122549 Fixes #122549 --- .../ice-unexpected-inference-var-122549.rs | 29 ++++++++ ...ice-unexpected-inference-var-122549.stderr | 67 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 tests/ui/const-generics/ice-unexpected-inference-var-122549.rs create mode 100644 tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr diff --git a/tests/ui/const-generics/ice-unexpected-inference-var-122549.rs b/tests/ui/const-generics/ice-unexpected-inference-var-122549.rs new file mode 100644 index 0000000000000..126ea667290d3 --- /dev/null +++ b/tests/ui/const-generics/ice-unexpected-inference-var-122549.rs @@ -0,0 +1,29 @@ +// Regression test for https://github.com/rust-lang/rust/issues/122549 +// was fixed by https://github.com/rust-lang/rust/pull/122749 + +trait ConstChunksExactTrait { + fn const_chunks_exact(&self) -> ConstChunksExact<'a, T, { N }>; + //~^ ERROR undeclared lifetime +} + +impl ConstChunksExactTrait for [T] {} +//~^ ERROR not all trait items implemented, missing: `const_chunks_exact` +struct ConstChunksExact<'rem, T: 'a, const N: usize> {} +//~^ ERROR use of undeclared lifetime name `'a` +//~^^ ERROR lifetime parameter +//~^^^ ERROR type parameter +impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> { +//~^ ERROR the const parameter `N` is not constrained by the impl trait, self type, or predicates +//~^^ ERROR mismatched types + type Item = &'a [T; N]; +} + +fn main() { + let slice = &[1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + let mut iter = [[1, 2, 3], [4, 5, 6], [7, 8, 9]].iter(); + + for a in slice.const_chunks_exact::<3>() { + assert_eq!(a, iter.next().unwrap()); + } +} diff --git a/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr new file mode 100644 index 0000000000000..afad3388145c7 --- /dev/null +++ b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr @@ -0,0 +1,67 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/ice-unexpected-inference-var-122549.rs:5:70 + | +LL | fn const_chunks_exact(&self) -> ConstChunksExact<'a, T, { N }>; + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn const_chunks_exact<'a, const N: usize>(&self) -> ConstChunksExact<'a, T, { N }>; + | +++ +help: consider introducing lifetime `'a` here + | +LL | trait ConstChunksExactTrait<'a, T> { + | +++ + +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/ice-unexpected-inference-var-122549.rs:11:34 + | +LL | struct ConstChunksExact<'rem, T: 'a, const N: usize> {} + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `'a,` + +error[E0046]: not all trait items implemented, missing: `const_chunks_exact` + --> $DIR/ice-unexpected-inference-var-122549.rs:9:1 + | +LL | fn const_chunks_exact(&self) -> ConstChunksExact<'a, T, { N }>; + | ------------------------------------------------------------------------------- `const_chunks_exact` from trait +... +LL | impl ConstChunksExactTrait for [T] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `const_chunks_exact` in implementation + +error[E0392]: lifetime parameter `'rem` is never used + --> $DIR/ice-unexpected-inference-var-122549.rs:11:25 + | +LL | struct ConstChunksExact<'rem, T: 'a, const N: usize> {} + | ^^^^ unused lifetime parameter + | + = help: consider removing `'rem`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/ice-unexpected-inference-var-122549.rs:11:31 + | +LL | struct ConstChunksExact<'rem, T: 'a, const N: usize> {} + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/ice-unexpected-inference-var-122549.rs:15:13 + | +LL | impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> { + | ^^^^^^^^^^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0308]: mismatched types + --> $DIR/ice-unexpected-inference-var-122549.rs:15:66 + | +LL | impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> { + | ^^ expected `usize`, found `()` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0046, E0207, E0261, E0308, E0392. +For more information about an error, try `rustc --explain E0046`. From c00920c5daf8c9b6422639c947b5f6ce28241201 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 21 Mar 2024 12:57:39 -0700 Subject: [PATCH 8/8] Avoid noop rewrite of issues.txt This can trigger incremental rebuilds since incr doesn't realize nothing changed. --- src/tools/tidy/src/ui_tests.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 22927cffd1b9b..fa24447f69992 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -183,9 +183,10 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { } }); - // if an excluded file is renamed, it must be removed from this list + // if there are any file names remaining, they were moved on the fs. + // our data must remain up to date, so it must be removed from issues.txt // do this automatically on bless, otherwise issue a tidy error - if bless { + if bless && !remaining_issue_names.is_empty() { let issues_txt_header = r#" /* ============================================================