Skip to content

Commit 27d6200

Browse files
committed
Auto merge of rust-lang#140708 - GuillaumeGomez:rollup-egt3nl9, r=GuillaumeGomez
Rollup of 4 pull requests Successful merges: - rust-lang#136183 (Update iterator.rs to use arrays by value) - rust-lang#139966 (coverage: Only merge adjacent coverage spans) - rust-lang#140692 (Rename `graph::implementation::Graph` to `LinkedGraph`) - rust-lang#140703 (Handle PR not found in post-merge workflow) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 1a95cc6 + ee0d68f commit 27d6200

File tree

147 files changed

+3166
-2111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

147 files changed

+3166
-2111
lines changed

.github/workflows/post-merge.yml

+7
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,19 @@ jobs:
2525
env:
2626
GH_TOKEN: ${{ github.token }}
2727
run: |
28+
# Give GitHub some time to propagate the information that the PR was merged
29+
sleep 60
30+
2831
# Get closest bors merge commit
2932
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
3033
echo "Parent: ${PARENT_COMMIT}"
3134
3235
# Find PR for the current commit
3336
HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'`
37+
if [ -z "${HEAD_PR}" ]; then
38+
echo "PR for commit SHA ${{ github.sha }} not found, exiting"
39+
exit 1
40+
fi
3441
echo "HEAD: ${{ github.sha }} (#${HEAD_PR})"
3542
3643
cd src/ci/citool

compiler/rustc_data_structures/src/graph/implementation/mod.rs renamed to compiler/rustc_data_structures/src/graph/linked_graph/mod.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! A graph module for use in dataflow, region resolution, and elsewhere.
1+
//! See [`LinkedGraph`].
22
//!
33
//! # Interface details
44
//!
@@ -28,7 +28,23 @@ use tracing::debug;
2828
#[cfg(test)]
2929
mod tests;
3030

31-
pub struct Graph<N, E> {
31+
/// A concrete graph implementation that supports:
32+
/// - Nodes and/or edges labelled with custom data types (`N` and `E` respectively).
33+
/// - Incremental addition of new nodes/edges (but not removal).
34+
/// - Flat storage of node/edge data in a pair of vectors.
35+
/// - Iteration over any node's out-edges or in-edges, via linked lists
36+
/// threaded through the node/edge data.
37+
///
38+
/// # Caution
39+
/// This is an older graph implementation that is still used by some pieces
40+
/// of diagnostic/debugging code. New code that needs a graph data structure
41+
/// should consider using `VecGraph` instead, or implementing its own
42+
/// special-purpose graph with the specific features needed.
43+
///
44+
/// This graph implementation predates the later [graph traits](crate::graph),
45+
/// and does not implement those traits, so it has its own implementations of a
46+
/// few basic graph algorithms.
47+
pub struct LinkedGraph<N, E> {
3248
nodes: Vec<Node<N>>,
3349
edges: Vec<Edge<E>>,
3450
}
@@ -71,13 +87,13 @@ impl NodeIndex {
7187
}
7288
}
7389

74-
impl<N: Debug, E: Debug> Graph<N, E> {
75-
pub fn new() -> Graph<N, E> {
76-
Graph { nodes: Vec::new(), edges: Vec::new() }
90+
impl<N: Debug, E: Debug> LinkedGraph<N, E> {
91+
pub fn new() -> Self {
92+
Self { nodes: Vec::new(), edges: Vec::new() }
7793
}
7894

79-
pub fn with_capacity(nodes: usize, edges: usize) -> Graph<N, E> {
80-
Graph { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) }
95+
pub fn with_capacity(nodes: usize, edges: usize) -> Self {
96+
Self { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) }
8197
}
8298

8399
// # Simple accessors
@@ -249,7 +265,7 @@ impl<N: Debug, E: Debug> Graph<N, E> {
249265
// # Iterators
250266

251267
pub struct AdjacentEdges<'g, N, E> {
252-
graph: &'g Graph<N, E>,
268+
graph: &'g LinkedGraph<N, E>,
253269
direction: Direction,
254270
next: EdgeIndex,
255271
}
@@ -285,15 +301,15 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
285301
}
286302

287303
pub struct DepthFirstTraversal<'g, N, E> {
288-
graph: &'g Graph<N, E>,
304+
graph: &'g LinkedGraph<N, E>,
289305
stack: Vec<NodeIndex>,
290306
visited: DenseBitSet<usize>,
291307
direction: Direction,
292308
}
293309

294310
impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> {
295311
pub fn with_start_node(
296-
graph: &'g Graph<N, E>,
312+
graph: &'g LinkedGraph<N, E>,
297313
start_node: NodeIndex,
298314
direction: Direction,
299315
) -> Self {

compiler/rustc_data_structures/src/graph/implementation/tests.rs renamed to compiler/rustc_data_structures/src/graph/linked_graph/tests.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use tracing::debug;
22

3-
use crate::graph::implementation::*;
3+
use super::{Debug, LinkedGraph, NodeIndex};
44

5-
type TestGraph = Graph<&'static str, &'static str>;
5+
type TestGraph = LinkedGraph<&'static str, &'static str>;
66

77
fn create_graph() -> TestGraph {
8-
let mut graph = Graph::new();
8+
let mut graph = LinkedGraph::new();
99

1010
// Create a simple graph
1111
//
@@ -56,7 +56,7 @@ fn each_edge() {
5656
}
5757

5858
fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(
59-
graph: &Graph<N, E>,
59+
graph: &LinkedGraph<N, E>,
6060
start_index: NodeIndex,
6161
start_data: N,
6262
expected_incoming: &[(E, N)],

compiler/rustc_data_structures/src/graph/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use rustc_index::Idx;
22

33
pub mod dominators;
4-
pub mod implementation;
54
pub mod iterate;
5+
pub mod linked_graph;
66
mod reference;
77
pub mod reversed;
88
pub mod scc;

compiler/rustc_incremental/src/assert_dep_graph.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use std::fs::{self, File};
3838
use std::io::Write;
3939

4040
use rustc_data_structures::fx::FxIndexSet;
41-
use rustc_data_structures::graph::implementation::{Direction, INCOMING, NodeIndex, OUTGOING};
41+
use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, NodeIndex, OUTGOING};
4242
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
4343
use rustc_hir::intravisit::{self, Visitor};
4444
use rustc_middle::dep_graph::{

compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
use std::fmt;
44

55
use rustc_data_structures::fx::FxHashSet;
6-
use rustc_data_structures::graph::implementation::{
7-
Direction, Graph, INCOMING, NodeIndex, OUTGOING,
6+
use rustc_data_structures::graph::linked_graph::{
7+
Direction, INCOMING, LinkedGraph, NodeIndex, OUTGOING,
88
};
99
use rustc_data_structures::intern::Interned;
1010
use rustc_data_structures::unord::UnordSet;
@@ -118,7 +118,7 @@ struct RegionAndOrigin<'tcx> {
118118
origin: SubregionOrigin<'tcx>,
119119
}
120120

121-
type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
121+
type RegionGraph<'tcx> = LinkedGraph<(), Constraint<'tcx>>;
122122

123123
struct LexicalResolver<'cx, 'tcx> {
124124
region_rels: &'cx RegionRelations<'cx, 'tcx>,
@@ -668,7 +668,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
668668
fn construct_graph(&self) -> RegionGraph<'tcx> {
669669
let num_vars = self.num_vars();
670670

671-
let mut graph = Graph::new();
671+
let mut graph = LinkedGraph::new();
672672

673673
for _ in 0..num_vars {
674674
graph.add_node(());

compiler/rustc_mir_transform/src/coverage/mappings.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
9191
// When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need
9292
// to give the same treatment to _all_ functions, because `llvm-cov`
9393
// seems to ignore functions that don't have any ordinary code spans.
94-
if let Some(span) = hir_info.fn_sig_span_extended {
94+
if let Some(span) = hir_info.fn_sig_span {
9595
code_mappings.push(CodeMapping { span, bcb: START_BCB });
9696
}
9797
} else {

compiler/rustc_mir_transform/src/coverage/mod.rs

+11-21
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,9 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
268268
struct ExtractedHirInfo {
269269
function_source_hash: u64,
270270
is_async_fn: bool,
271-
/// The span of the function's signature, extended to the start of `body_span`.
271+
/// The span of the function's signature, if available.
272272
/// Must have the same context and filename as the body span.
273-
fn_sig_span_extended: Option<Span>,
273+
fn_sig_span: Option<Span>,
274274
body_span: Span,
275275
/// "Holes" are regions within the function body (or its expansions) that
276276
/// should not be included in coverage spans for this function
@@ -308,30 +308,20 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
308308

309309
// The actual signature span is only used if it has the same context and
310310
// filename as the body, and precedes the body.
311-
let fn_sig_span_extended = maybe_fn_sig
312-
.map(|fn_sig| fn_sig.span)
313-
.filter(|&fn_sig_span| {
314-
let source_map = tcx.sess.source_map();
315-
let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
316-
317-
fn_sig_span.eq_ctxt(body_span)
318-
&& fn_sig_span.hi() <= body_span.lo()
319-
&& file_idx(fn_sig_span) == file_idx(body_span)
320-
})
321-
// If so, extend it to the start of the body span.
322-
.map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()));
311+
let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| {
312+
let source_map = tcx.sess.source_map();
313+
let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
314+
315+
fn_sig_span.eq_ctxt(body_span)
316+
&& fn_sig_span.hi() <= body_span.lo()
317+
&& file_idx(fn_sig_span) == file_idx(body_span)
318+
});
323319

324320
let function_source_hash = hash_mir_source(tcx, hir_body);
325321

326322
let hole_spans = extract_hole_spans_from_hir(tcx, hir_body);
327323

328-
ExtractedHirInfo {
329-
function_source_hash,
330-
is_async_fn,
331-
fn_sig_span_extended,
332-
body_span,
333-
hole_spans,
334-
}
324+
ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans }
335325
}
336326

337327
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 {

compiler/rustc_mir_transform/src/coverage/spans.rs

+47-71
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
use std::collections::VecDeque;
2-
use std::iter;
3-
41
use rustc_data_structures::fx::FxHashSet;
52
use rustc_middle::mir;
63
use rustc_middle::ty::TyCtxt;
74
use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span};
8-
use tracing::{debug, debug_span, instrument};
5+
use tracing::instrument;
96

107
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
118
use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir};
@@ -42,12 +39,12 @@ pub(super) fn extract_refined_covspans<'tcx>(
4239
return;
4340
}
4441

45-
// Also add the adjusted function signature span, if available.
42+
// Also add the function signature span, if available.
4643
// Otherwise, add a fake span at the start of the body, to avoid an ugly
4744
// gap between the start of the body and the first real span.
4845
// FIXME: Find a more principled way to solve this problem.
4946
covspans.push(SpanFromMir::for_fn_sig(
50-
hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()),
47+
hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()),
5148
));
5249

5350
// First, perform the passes that need macro information.
@@ -83,24 +80,17 @@ pub(super) fn extract_refined_covspans<'tcx>(
8380
holes.sort_by(|a, b| compare_spans(a.span, b.span));
8481
holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b));
8582

86-
// Split the covspans into separate buckets that don't overlap any holes.
87-
let buckets = divide_spans_into_buckets(covspans, &holes);
88-
89-
for covspans in buckets {
90-
let _span = debug_span!("processing bucket", ?covspans).entered();
83+
// Discard any span that overlaps with a hole.
84+
discard_spans_overlapping_holes(&mut covspans, &holes);
9185

92-
let mut covspans = remove_unwanted_overlapping_spans(covspans);
93-
debug!(?covspans, "after removing overlaps");
86+
// Perform more refinement steps after holes have been dealt with.
87+
let mut covspans = remove_unwanted_overlapping_spans(covspans);
88+
covspans.dedup_by(|b, a| a.merge_if_eligible(b));
9489

95-
// Do one last merge pass, to simplify the output.
96-
covspans.dedup_by(|b, a| a.merge_if_eligible(b));
97-
debug!(?covspans, "after merge");
98-
99-
code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| {
100-
// Each span produced by the refiner represents an ordinary code region.
101-
mappings::CodeMapping { span, bcb }
102-
}));
103-
}
90+
code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| {
91+
// Each span produced by the refiner represents an ordinary code region.
92+
mappings::CodeMapping { span, bcb }
93+
}));
10494
}
10595

10696
/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate
@@ -142,52 +132,36 @@ fn shrink_visible_macro_spans(tcx: TyCtxt<'_>, covspans: &mut Vec<SpanFromMir>)
142132
}
143133
}
144134

145-
/// Uses the holes to divide the given covspans into buckets, such that:
146-
/// - No span in any hole overlaps a bucket (discarding spans if necessary).
147-
/// - The spans in each bucket are strictly after all spans in previous buckets,
148-
/// and strictly before all spans in subsequent buckets.
135+
/// Discard all covspans that overlap a hole.
149136
///
150-
/// The lists of covspans and holes must be sorted.
151-
/// The resulting buckets are sorted relative to each other, and each bucket's
152-
/// contents are sorted.
153-
#[instrument(level = "debug")]
154-
fn divide_spans_into_buckets(input_covspans: Vec<Covspan>, holes: &[Hole]) -> Vec<Vec<Covspan>> {
155-
debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le()));
137+
/// The lists of covspans and holes must be sorted, and any holes that overlap
138+
/// with each other must have already been merged.
139+
fn discard_spans_overlapping_holes(covspans: &mut Vec<Covspan>, holes: &[Hole]) {
140+
debug_assert!(covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le()));
156141
debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le()));
142+
debug_assert!(holes.array_windows().all(|[a, b]| !a.span.overlaps_or_adjacent(b.span)));
143+
144+
let mut curr_hole = 0usize;
145+
let mut overlaps_hole = |covspan: &Covspan| -> bool {
146+
while let Some(hole) = holes.get(curr_hole) {
147+
// Both lists are sorted, so we can permanently skip any holes that
148+
// end before the start of the current span.
149+
if hole.span.hi() <= covspan.span.lo() {
150+
curr_hole += 1;
151+
continue;
152+
}
157153

158-
// Now we're ready to start grouping spans into buckets separated by holes.
159-
160-
let mut input_covspans = VecDeque::from(input_covspans);
161-
162-
// For each hole:
163-
// - Identify the spans that are entirely or partly before the hole.
164-
// - Discard any that overlap with the hole.
165-
// - Add the remaining identified spans to the corresponding bucket.
166-
let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>();
167-
for (hole, bucket) in holes.iter().zip(&mut buckets) {
168-
bucket.extend(
169-
drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi())
170-
.filter(|c| !c.span.overlaps(hole.span)),
171-
);
172-
}
173-
174-
// Any remaining spans form their own final bucket, after the final hole.
175-
// (If there were no holes, this will just be all of the initial spans.)
176-
buckets.push(Vec::from(input_covspans));
154+
return hole.span.overlaps(covspan.span);
155+
}
177156

178-
buckets
179-
}
157+
// No holes left, so this covspan doesn't overlap with any holes.
158+
false
159+
};
180160

181-
/// Similar to `.drain(..)`, but stops just before it would remove an item not
182-
/// satisfying the predicate.
183-
fn drain_front_while<'a, T>(
184-
queue: &'a mut VecDeque<T>,
185-
mut pred_fn: impl FnMut(&T) -> bool,
186-
) -> impl Iterator<Item = T> {
187-
iter::from_fn(move || queue.pop_front_if(|x| pred_fn(x)))
161+
covspans.retain(|covspan| !overlaps_hole(covspan));
188162
}
189163

190-
/// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines"
164+
/// Takes a list of sorted spans extracted from MIR, and "refines"
191165
/// those spans by removing spans that overlap in unwanted ways.
192166
#[instrument(level = "debug")]
193167
fn remove_unwanted_overlapping_spans(sorted_spans: Vec<Covspan>) -> Vec<Covspan> {
@@ -227,19 +201,21 @@ struct Covspan {
227201
}
228202

229203
impl Covspan {
230-
/// If `self` and `other` can be merged (i.e. they have the same BCB),
231-
/// mutates `self.span` to also include `other.span` and returns true.
204+
/// If `self` and `other` can be merged, mutates `self.span` to also
205+
/// include `other.span` and returns true.
232206
///
233-
/// Note that compatible covspans can be merged even if their underlying
234-
/// spans are not overlapping/adjacent; any space between them will also be
235-
/// part of the merged covspan.
207+
/// Two covspans can be merged if they have the same BCB, and they are
208+
/// overlapping or adjacent.
236209
fn merge_if_eligible(&mut self, other: &Self) -> bool {
237-
if self.bcb != other.bcb {
238-
return false;
210+
let eligible_for_merge =
211+
|a: &Self, b: &Self| (a.bcb == b.bcb) && a.span.overlaps_or_adjacent(b.span);
212+
213+
if eligible_for_merge(self, other) {
214+
self.span = self.span.to(other.span);
215+
true
216+
} else {
217+
false
239218
}
240-
241-
self.span = self.span.to(other.span);
242-
true
243219
}
244220
}
245221

0 commit comments

Comments
 (0)