From 3e43bf0feedc9b7ece1459572f5e79d812d6915b Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 5 Jan 2024 21:22:42 +0000 Subject: [PATCH 1/9] os::net: expanding TcpStreamExt for Linux with `tcp_deferaccept`. allows for socket to process only when there is data to process, the option sets a number of seconds until the data is ready. --- library/std/src/os/net/linux_ext/tcp.rs | 51 +++++++++++++++++++++++ library/std/src/os/net/linux_ext/tests.rs | 25 +++++++++++ library/std/src/sys/pal/unix/net.rs | 12 ++++++ 3 files changed, 88 insertions(+) diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index 5e9ee65a4152e..15b11cd08bfda 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -53,6 +53,49 @@ pub trait TcpStreamExt: Sealed { /// ``` #[unstable(feature = "tcp_quickack", issue = "96256")] fn quickack(&self) -> io::Result; + + /// A socket listener will be awakened solely when data arrives. + /// + /// The `accept` argument set the delay in seconds until the + /// data is available to read, reducing the number of short lived + /// connections without data to process. + /// Contrary to other platforms `SO_ACCEPTFILTER` feature equivalent, there is + /// no necessity to set it after the `listen` call. + /// + /// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html) + /// + /// # Examples + /// + /// ```no run + /// #![feature(tcp_deferaccept)] + /// use std::net::TcpStream; + /// use std::os::linux::net::TcpStreamExt; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_deferaccept(1).expect("set_deferaccept call failed"); + /// ``` + #[unstable(feature = "tcp_deferaccept", issue = "119639")] + fn set_deferaccept(&self, accept: u32) -> io::Result<()>; + + /// Gets the accept delay value (in seconds) of the `TCP_DEFER_ACCEPT` option. + /// + /// For more information about this option, see [`TcpStreamExt::set_deferaccept`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_deferaccept)] + /// use std::net::TcpStream; + /// use std::os::linux::net::TcpStreamExt; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_deferaccept(1).expect("set_deferaccept call failed"); + /// assert_eq!(stream.deferaccept().unwrap_or(0), 1); + /// ``` + #[unstable(feature = "tcp_deferaccept", issue = "119639")] + fn deferaccept(&self) -> io::Result; } #[unstable(feature = "tcp_quickack", issue = "96256")] @@ -67,4 +110,12 @@ impl TcpStreamExt for net::TcpStream { fn quickack(&self) -> io::Result { self.as_inner().as_inner().quickack() } + + fn set_deferaccept(&self, accept: u32) -> io::Result<()> { + self.as_inner().as_inner().set_deferaccept(accept) + } + + fn deferaccept(&self) -> io::Result { + self.as_inner().as_inner().deferaccept() + } } diff --git a/library/std/src/os/net/linux_ext/tests.rs b/library/std/src/os/net/linux_ext/tests.rs index 2db4deed03630..b9d621c7cfa24 100644 --- a/library/std/src/os/net/linux_ext/tests.rs +++ b/library/std/src/os/net/linux_ext/tests.rs @@ -26,3 +26,28 @@ fn quickack() { t!(stream.set_quickack(false)); assert_eq!(false, t!(stream.quickack())); } + +#[test] +fn deferaccept() { + use crate::{ + net::{test::next_test_ip4, TcpListener, TcpStream}, + os::net::linux_ext::tcp::TcpStreamExt, + }; + + macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; + } + + let addr = next_test_ip4(); + let _listener = t!(TcpListener::bind(&addr)); + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + stream.set_deferaccept(1).expect("set_deferaccept failed"); + assert_eq!(stream.deferaccept().unwrap(), 1); + stream.set_deferaccept(0).expect("set_deferaccept failed"); + assert_eq!(stream.deferaccept().unwrap(), 0); +} diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 8f537de7026f5..4f11ebd0324cc 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -441,6 +441,18 @@ impl Socket { Ok(raw != 0) } + // bionic libc makes no use of this flag + #[cfg(target_os = "linux")] + pub fn set_deferaccept(&self, accept: u32) -> io::Result<()> { + setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, accept as c_int) + } + + #[cfg(target_os = "linux")] + pub fn deferaccept(&self) -> io::Result { + let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)?; + Ok(raw as u32) + } + #[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 e5fa6ec845e458984e361e601d603fa050e992e4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 20 Feb 2024 10:25:06 +0000 Subject: [PATCH 2/9] triagebot: add queue notifications Signed-off-by: David Wood --- triagebot.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 1a30399e46c03..6634909d3fdcf 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -423,6 +423,10 @@ changelog-branch = "master" [shortcut] +[mentions."triagebot.toml"] +message = "`triagebot.toml` has been modified, there may have been changes to the review queue." +cc = ["@davidtwco", "@wesleywiser"] + [mentions."compiler/rustc_codegen_cranelift"] cc = ["@bjorn3"] From ec91209f964182655cc1330c0a6f79c3e8bca7df Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Feb 2024 20:38:07 +1100 Subject: [PATCH 3/9] coverage: Eagerly deduplicate covspans with the same span --- .../src/coverage/spans/from_mir.rs | 15 ++++++++++----- tests/coverage/closure_macro.cov-map | 9 ++++----- tests/coverage/closure_macro_async.cov-map | 9 ++++----- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 2db358379fe51..b91ab811918a7 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -52,14 +52,19 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( // - Span A extends further left, or // - Both have the same start and span A extends further right .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse()) - // If both spans are equal, sort the BCBs in dominator order, - // so that dominating BCBs come before other BCBs they dominate. - .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)) - // If two spans are otherwise identical, put closure spans first, - // as this seems to be what the refinement step expects. + // If two spans have the same lo & hi, put closure spans first, + // as they take precedence over non-closure spans. .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) + // After deduplication, we want to keep only the most-dominated BCB. + .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) }); + // Among covspans with the same span, keep only one. Closure spans take + // precedence, otherwise keep the one with the most-dominated BCB. + // (Ideally we should try to preserve _all_ non-dominating BCBs, but that + // requires a lot more complexity in the span refiner, for little benefit.) + initial_spans.dedup_by(|b, a| a.span.source_equal(b.span)); + initial_spans } diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index 571e5564b659c..e43ed1f76f366 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -7,18 +7,17 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) Function name: closure_macro::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) -Number of file 0 mappings: 7 +Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18) = (c0 - c1) -- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 15) to (start + 0, 84) = (c0 - c1) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 49ec767eab33e..212b67a8a3e1d 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -15,18 +15,17 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 35, 1) to (start + 0, 43) Function name: closure_macro_async::test::{closure#0} -Raw bytes (43): 0x[01, 01, 02, 01, 05, 05, 02, 07, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 12, 00, 13, 02, 00, 12, 00, 13, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub) -Number of file 0 mappings: 7 +Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 35, 43) to (start + 1, 33) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18) = (c0 - c1) -- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 15) to (start + 0, 84) = (c0 - c1) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) From c40261da11a58247822c9297993eb2142d8d53a2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Feb 2024 20:49:47 +1100 Subject: [PATCH 4/9] coverage: Remove `pending_dups` from the span refiner --- .../rustc_mir_transform/src/coverage/spans.rs | 180 ++---------------- 1 file changed, 16 insertions(+), 164 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 934e77e7deb0a..c2e348cb7131b 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -61,7 +61,7 @@ pub(super) fn generate_coverage_spans( hir_info, basic_coverage_blocks, ); - let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans); + let coverage_spans = SpansRefiner::refine_sorted_spans(sorted_spans); mappings.extend(coverage_spans.into_iter().map(|RefinedCovspan { bcb, span, .. }| { // Each span produced by the generator represents an ordinary code region. BcbMapping { kind: BcbMappingKind::Code(bcb), span } @@ -88,8 +88,6 @@ pub(super) fn generate_coverage_spans( #[derive(Debug)] struct CurrCovspan { - /// This is used as the basis for [`PrevCovspan::original_span`], so it must - /// not be modified. span: Span, bcb: BasicCoverageBlock, is_closure: bool, @@ -102,7 +100,7 @@ impl CurrCovspan { fn into_prev(self) -> PrevCovspan { let Self { span, bcb, is_closure } = self; - PrevCovspan { original_span: span, span, bcb, merged_spans: vec![span], is_closure } + PrevCovspan { span, bcb, merged_spans: vec![span], is_closure } } fn into_refined(self) -> RefinedCovspan { @@ -115,7 +113,6 @@ impl CurrCovspan { #[derive(Debug)] struct PrevCovspan { - original_span: Span, span: Span, bcb: BasicCoverageBlock, /// List of all the original spans from MIR that have been merged into this @@ -142,35 +139,8 @@ impl PrevCovspan { } } - fn into_dup(self) -> DuplicateCovspan { - let Self { original_span, span, bcb, merged_spans: _, is_closure } = self; - // Only unmodified spans end up in `pending_dups`. - debug_assert_eq!(original_span, span); - DuplicateCovspan { span, bcb, is_closure } - } - - fn refined_copy(&self) -> RefinedCovspan { - let &Self { original_span: _, span, bcb, merged_spans: _, is_closure } = self; - RefinedCovspan { span, bcb, is_closure } - } - - fn into_refined(self) -> RefinedCovspan { - self.refined_copy() - } -} - -#[derive(Debug)] -struct DuplicateCovspan { - span: Span, - bcb: BasicCoverageBlock, - is_closure: bool, -} - -impl DuplicateCovspan { - /// Returns a copy of this covspan, as a [`RefinedCovspan`]. - /// Should only be called in places that would otherwise clone this covspan. fn refined_copy(&self) -> RefinedCovspan { - let &Self { span, bcb, is_closure } = self; + let &Self { span, bcb, merged_spans: _, is_closure } = self; RefinedCovspan { span, bcb, is_closure } } @@ -205,10 +175,7 @@ impl RefinedCovspan { /// * Merge spans that represent continuous (both in source code and control flow), non-branching /// execution /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) -struct SpansRefiner<'a> { - /// The BasicCoverageBlock Control Flow Graph (BCB CFG). - basic_coverage_blocks: &'a CoverageGraph, - +struct SpansRefiner { /// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative /// dominance between the `BasicCoverageBlock`s of equal `Span`s. sorted_spans_iter: std::vec::IntoIter, @@ -223,36 +190,22 @@ struct SpansRefiner<'a> { /// If that `curr` was discarded, `prev` retains its value from the previous iteration. some_prev: Option, - /// One or more coverage spans with the same `Span` but different `BasicCoverageBlock`s, and - /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. - /// If a new `curr` span also fits this criteria (compared to an existing list of - /// `pending_dups`), that `curr` moves to `prev` before possibly being added to - /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups` - /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev` - /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a - /// `prev` with a matching `Span`) - pending_dups: Vec, - /// The final coverage spans to add to the coverage map. A `Counter` or `Expression` /// will also be injected into the MIR for each BCB that has associated spans. refined_spans: Vec, } -impl<'a> SpansRefiner<'a> { +impl SpansRefiner { /// Takes the initial list of (sorted) spans extracted from MIR, and "refines" /// them by merging compatible adjacent spans, removing redundant spans, /// and carving holes in spans when they overlap in unwanted ways. - fn refine_sorted_spans( - basic_coverage_blocks: &'a CoverageGraph, - sorted_spans: Vec, - ) -> Vec { + fn refine_sorted_spans(sorted_spans: Vec) -> Vec { + let sorted_spans_len = sorted_spans.len(); let this = Self { - basic_coverage_blocks, sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, some_prev: None, - pending_dups: Vec::new(), - refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), + refined_spans: Vec::with_capacity(sorted_spans_len), }; this.to_refined_spans() @@ -292,21 +245,11 @@ impl<'a> SpansRefiner<'a> { self.take_curr(); // Discards curr. } else if curr.is_closure { self.carve_out_span_for_closure(); - } else if prev.original_span == prev.span && prev.span == curr.span { - // Prev and curr have the same span, and prev's span hasn't - // been modified by other spans. - self.update_pending_dups(); } else { self.cutoff_prev_at_overlapping_curr(); } } - // Drain any remaining dups into the output. - for dup in self.pending_dups.drain(..) { - debug!(" ...adding at least one pending dup={:?}", dup); - self.refined_spans.push(dup.into_refined()); - } - // There is usually a final span remaining in `prev` after the loop ends, // so add it to the output as well. if let Some(prev) = self.some_prev.take() { @@ -359,36 +302,6 @@ impl<'a> SpansRefiner<'a> { self.some_prev.take().unwrap_or_else(|| bug!("some_prev is None (take_prev)")) } - /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the - /// `pending_dups` spans), then one of the following two things happened during the previous - /// iteration: - /// * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups - /// (in which case there should be at least two spans in `pending_dups`); or - /// * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case - /// `pending_dups` could have as few as one span) - /// In either case, no more spans will match the span of `pending_dups`, so - /// add the `pending_dups` if they don't overlap `curr`, and clear the list. - fn maybe_flush_pending_dups(&mut self) { - let Some(last_dup) = self.pending_dups.last() else { return }; - if last_dup.span == self.prev().span { - return; - } - - debug!( - " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ - previous iteration, or prev started a new disjoint span" - ); - if last_dup.span.hi() <= self.curr().span.lo() { - for dup in self.pending_dups.drain(..) { - debug!(" ...adding at least one pending={:?}", dup); - self.refined_spans.push(dup.into_refined()); - } - } else { - self.pending_dups.clear(); - } - assert!(self.pending_dups.is_empty()); - } - /// Advance `prev` to `curr` (if any), and `curr` to the next coverage span in sorted order. fn next_coverage_span(&mut self) -> bool { if let Some(curr) = self.some_curr.take() { @@ -408,7 +321,6 @@ impl<'a> SpansRefiner<'a> { ); } else { self.some_curr = Some(CurrCovspan::new(curr.span, curr.bcb, curr.is_closure)); - self.maybe_flush_pending_dups(); return true; } } @@ -433,13 +345,6 @@ impl<'a> SpansRefiner<'a> { let mut pre_closure = self.prev().refined_copy(); pre_closure.span = pre_closure.span.with_hi(left_cutoff); debug!(" prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure); - - for mut dup in self.pending_dups.iter().map(DuplicateCovspan::refined_copy) { - dup.span = dup.span.with_hi(left_cutoff); - debug!(" ...and at least one pre_closure dup={:?}", dup); - self.refined_spans.push(dup); - } - self.refined_spans.push(pre_closure); } @@ -448,58 +353,9 @@ impl<'a> SpansRefiner<'a> { self.prev_mut().span = self.prev().span.with_lo(right_cutoff); debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev()); - for dup in &mut self.pending_dups { - debug!(" ...and at least one overlapping dup={:?}", dup); - dup.span = dup.span.with_lo(right_cutoff); - } - // Prevent this curr from becoming prev. let closure_covspan = self.take_curr().into_refined(); self.refined_spans.push(closure_covspan); // since self.prev() was already updated - } else { - self.pending_dups.clear(); - } - } - - /// Called if `curr.span` equals `prev.original_span` (and potentially equal to all - /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed. - /// If prev.span() was merged into other spans (with matching BCB, for instance), - /// `prev.span.hi()` will be greater than (further right of) `prev.original_span.hi()`. - /// If prev.span() was split off to the right of a closure, prev.span().lo() will be - /// greater than prev.original_span.lo(). The actual span of `prev.original_span` is - /// not as important as knowing that `prev()` **used to have the same span** as `curr()`, - /// which means their sort order is still meaningful for determining the dominator - /// relationship. - /// - /// When two coverage spans have the same `Span`, dominated spans can be discarded; but if - /// neither coverage span dominates the other, both (or possibly more than two) are held, - /// until their disposition is determined. In this latter case, the `prev` dup is moved into - /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. - fn update_pending_dups(&mut self) { - let prev_bcb = self.prev().bcb; - let curr_bcb = self.curr().bcb; - - // Equal coverage spans are ordered by dominators before dominated (if any), so it should be - // impossible for `curr` to dominate any previous coverage span. - debug_assert!(!self.basic_coverage_blocks.dominates(curr_bcb, prev_bcb)); - - // `prev` is a duplicate of `curr`, so add it to the list of pending dups. - // If it dominates `curr`, it will be removed by the subsequent discard step. - let prev = self.take_prev().into_dup(); - debug!(?prev, "adding prev to pending dups"); - self.pending_dups.push(prev); - - let initial_pending_count = self.pending_dups.len(); - if initial_pending_count > 0 { - self.pending_dups - .retain(|dup| !self.basic_coverage_blocks.dominates(dup.bcb, curr_bcb)); - - let n_discarded = initial_pending_count - self.pending_dups.len(); - if n_discarded > 0 { - debug!( - " discarded {n_discarded} of {initial_pending_count} pending_dups that dominated curr", - ); - } } } @@ -516,19 +372,15 @@ impl<'a> SpansRefiner<'a> { if it has statements that end before curr; prev={:?}", self.prev() ); - if self.pending_dups.is_empty() { - let curr_span = self.curr().span; - self.prev_mut().cutoff_statements_at(curr_span.lo()); - if self.prev().merged_spans.is_empty() { - debug!(" ... no non-overlapping statements to add"); - } else { - debug!(" ... adding modified prev={:?}", self.prev()); - let prev = self.take_prev().into_refined(); - self.refined_spans.push(prev); - } + + let curr_span = self.curr().span; + self.prev_mut().cutoff_statements_at(curr_span.lo()); + if self.prev().merged_spans.is_empty() { + debug!(" ... no non-overlapping statements to add"); } else { - // with `pending_dups`, `prev` cannot have any statements that don't overlap - self.pending_dups.clear(); + debug!(" ... adding modified prev={:?}", self.prev()); + let prev = self.take_prev().into_refined(); + self.refined_spans.push(prev); } } } From 3a83b279bef65f8b727d33d1c7a80e5d2432f5aa Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 18 Feb 2024 20:54:10 +1100 Subject: [PATCH 5/9] coverage: Simplify (non-closure) covspans truncating each other --- compiler/rustc_mir_transform/src/coverage/spans.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index c2e348cb7131b..98fb1d8e1c940 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -132,11 +132,13 @@ impl PrevCovspan { self.merged_spans.push(other.span); } - fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) { + fn cutoff_statements_at(mut self, cutoff_pos: BytePos) -> Option { self.merged_spans.retain(|span| span.hi() <= cutoff_pos); if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() { self.span = self.span.with_hi(max_hi); } + + if self.merged_spans.is_empty() { None } else { Some(self.into_refined()) } } fn refined_copy(&self) -> RefinedCovspan { @@ -374,13 +376,11 @@ impl SpansRefiner { ); let curr_span = self.curr().span; - self.prev_mut().cutoff_statements_at(curr_span.lo()); - if self.prev().merged_spans.is_empty() { - debug!(" ... no non-overlapping statements to add"); - } else { - debug!(" ... adding modified prev={:?}", self.prev()); - let prev = self.take_prev().into_refined(); + if let Some(prev) = self.take_prev().cutoff_statements_at(curr_span.lo()) { + debug!("after cutoff, adding {prev:?}"); self.refined_spans.push(prev); + } else { + debug!("prev was eliminated by cutoff"); } } } From 5e0e5b1efb8a5776231b07c71e7c03ef016654b5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Feb 2024 02:55:40 +0100 Subject: [PATCH 6/9] Fix liveness analysis in the presence of never patterns --- compiler/rustc_hir/src/pat_util.rs | 11 +++++++++-- compiler/rustc_passes/src/liveness.rs | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index e605032718623..1eaab3d2acac3 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -71,14 +71,21 @@ impl hir::Pat<'_> { /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }`. /// - /// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited. + /// When encountering an or-pattern `p_0 | ... | p_n` only the first non-never pattern will be + /// visited. If they're all never patterns we visit nothing, which is ok since a never pattern + /// cannot have bindings. pub fn each_binding_or_first( &self, f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, Ident), ) { self.walk(|p| match &p.kind { PatKind::Or(ps) => { - ps[0].each_binding_or_first(f); + for p in *ps { + if !p.is_never_pattern() { + p.each_binding_or_first(f); + break; + } + } false } PatKind::Binding(bm, _, ident, _) => { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 3a8dc3775206c..487407014d178 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -526,8 +526,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn define_bindings_in_pat(&mut self, pat: &hir::Pat<'_>, mut succ: LiveNode) -> LiveNode { - // In an or-pattern, only consider the first pattern; any later patterns - // must have the same bindings, and we also consider the first pattern + // In an or-pattern, only consider the first non-never pattern; any later patterns + // must have the same bindings, and we also consider that pattern // to be the "authoritative" set of ids. pat.each_binding_or_first(&mut |_, hir_id, pat_sp, ident| { let ln = self.live_node(hir_id, pat_sp); From a17211b05c883eaeb4057f0a9207947bcbcc3688 Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Wed, 21 Feb 2024 16:49:01 +0100 Subject: [PATCH 7/9] Solaris linker does not support --strip-debug Fixes #121381 --- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 9f06f398288f2..1f3383815e226 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -626,7 +626,7 @@ impl<'a> Linker for GccLinker<'a> { // it does support --strip-all as a compatibility alias for -s. // The --strip-debug case is handled by running an external // `strip` utility as a separate step after linking. - if self.sess.target.os != "illumos" { + if !self.sess.target.is_like_solaris { self.linker_arg("--strip-debug"); } } From a233b1656e0311e6a9842546d2f4273a95ebf6d6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 Feb 2024 17:16:35 +0000 Subject: [PATCH 8/9] Add an ATB test --- .../associated-type-bounds/no-gat-position.rs | 18 ++++++++++++++++++ .../no-gat-position.stderr | 9 +++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/ui/associated-type-bounds/no-gat-position.rs create mode 100644 tests/ui/associated-type-bounds/no-gat-position.stderr diff --git a/tests/ui/associated-type-bounds/no-gat-position.rs b/tests/ui/associated-type-bounds/no-gat-position.rs new file mode 100644 index 0000000000000..01740e6242e98 --- /dev/null +++ b/tests/ui/associated-type-bounds/no-gat-position.rs @@ -0,0 +1,18 @@ +#![feature(associated_type_bounds)] + +// Test for . + +pub trait Iter { + type Item<'a>: 'a where Self: 'a; + + fn next<'a>(&'a mut self) -> Option>; + //~^ ERROR associated type bindings are not allowed here +} + +impl Iter for () { + type Item<'a> = &'a mut [()]; + + fn next<'a>(&'a mut self) -> Option> { None } +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/no-gat-position.stderr b/tests/ui/associated-type-bounds/no-gat-position.stderr new file mode 100644 index 0000000000000..5692b2c7d0902 --- /dev/null +++ b/tests/ui/associated-type-bounds/no-gat-position.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/no-gat-position.rs:8:56 + | +LL | fn next<'a>(&'a mut self) -> Option>; + | ^^^^^^^^^ associated type not allowed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0229`. From f8fbb7060c746cafc0d503b119e4ece019e1dcb5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 Feb 2024 17:31:53 +0000 Subject: [PATCH 9/9] Add a non-lifetime-binders test --- .../bad-suggestion-on-missing-assoc.rs | 26 ++++++++++++++ .../bad-suggestion-on-missing-assoc.stderr | 34 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs create mode 100644 tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs new file mode 100644 index 0000000000000..fc64381b961d4 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs @@ -0,0 +1,26 @@ +#![feature(generic_const_exprs)] +//~^ WARN the feature `generic_const_exprs` is incomplete +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +// Test for , +// which originally relied on associated_type_bounds, but was +// minimized away from that. + +trait TraitA { + type AsA; +} +trait TraitB { + type AsB; +} +trait TraitC {} + +fn foo() +where + for T: TraitA>, + //~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~| ERROR `impl Trait` is not allowed in bounds +{ +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr new file mode 100644 index 0000000000000..a4a79413a9be6 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr @@ -0,0 +1,34 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bad-suggestion-on-missing-assoc.rs:1:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bad-suggestion-on-missing-assoc.rs:3:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + +error: defaults for generic parameters are not allowed in `for<...>` binders + --> $DIR/bad-suggestion-on-missing-assoc.rs:20:9 + | +LL | for T: TraitA>, + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0562]: `impl Trait` is not allowed in bounds + --> $DIR/bad-suggestion-on-missing-assoc.rs:20:49 + | +LL | for T: TraitA>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error: aborting due to 2 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0562`.