Skip to content

Commit a173b9b

Browse files
committed
Auto merge of #149485 - matthiaskrgr:rollup-o4it1i3, r=matthiaskrgr
Rollup of 3 pull requests Successful merges: - #148169 (Fix bad intra-doc-link preprocessing) - #149471 (coverage: Store signature/body spans and branch spans in the expansion tree) - #149481 (ThreadId generation fallback path: avoid spurious yields) r? `@ghost` `@rustbot` modify labels: rollup
2 parents f40a70d + c0320dc commit a173b9b

File tree

17 files changed

+440
-64
lines changed

17 files changed

+440
-64
lines changed

compiler/rustc_mir_transform/src/coverage/expansion.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
22
use rustc_middle::mir;
3-
use rustc_middle::mir::coverage::BasicCoverageBlock;
3+
use rustc_middle::mir::coverage::{BasicCoverageBlock, BranchSpan};
44
use rustc_span::{ExpnId, ExpnKind, Span};
55

66
use crate::coverage::from_mir;
@@ -71,11 +71,21 @@ pub(crate) struct ExpnNode {
7171
/// This links an expansion node to its parent in the tree.
7272
pub(crate) call_site_expn_id: Option<ExpnId>,
7373

74+
/// Holds the function signature span, if it belongs to this expansion.
75+
/// Used by special-case code in span refinement.
76+
pub(crate) fn_sig_span: Option<Span>,
77+
/// Holds the function body span, if it belongs to this expansion.
78+
/// Used by special-case code in span refinement.
79+
pub(crate) body_span: Option<Span>,
80+
7481
/// Spans (and their associated BCBs) belonging to this expansion.
7582
pub(crate) spans: Vec<SpanWithBcb>,
7683
/// Expansions whose call-site is in this expansion.
7784
pub(crate) child_expn_ids: FxIndexSet<ExpnId>,
7885

86+
/// Branch spans (recorded during MIR building) belonging to this expansion.
87+
pub(crate) branch_spans: Vec<BranchSpan>,
88+
7989
/// Hole spans belonging to this expansion, to be carved out from the
8090
/// code spans during span refinement.
8191
pub(crate) hole_spans: Vec<Span>,
@@ -95,9 +105,14 @@ impl ExpnNode {
95105
call_site,
96106
call_site_expn_id,
97107

108+
fn_sig_span: None,
109+
body_span: None,
110+
98111
spans: vec![],
99112
child_expn_ids: FxIndexSet::default(),
100113

114+
branch_spans: vec![],
115+
101116
hole_spans: vec![],
102117
}
103118
}
@@ -142,6 +157,20 @@ pub(crate) fn build_expn_tree(
142157
}
143158
}
144159

160+
// If we have a span for the function signature, associate it with the
161+
// corresponding expansion tree node.
162+
if let Some(fn_sig_span) = hir_info.fn_sig_span
163+
&& let Some(node) = nodes.get_mut(&fn_sig_span.ctxt().outer_expn())
164+
{
165+
node.fn_sig_span = Some(fn_sig_span);
166+
}
167+
168+
// Also associate the body span with its expansion tree node.
169+
let body_span = hir_info.body_span;
170+
if let Some(node) = nodes.get_mut(&body_span.ctxt().outer_expn()) {
171+
node.body_span = Some(body_span);
172+
}
173+
145174
// Associate each hole span (extracted from HIR) with its corresponding
146175
// expansion tree node.
147176
for &hole_span in &hir_info.hole_spans {
@@ -150,5 +179,15 @@ pub(crate) fn build_expn_tree(
150179
node.hole_spans.push(hole_span);
151180
}
152181

182+
// Associate each branch span (recorded during MIR building) with its
183+
// corresponding expansion tree node.
184+
if let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() {
185+
for branch_span in &coverage_info_hi.branch_spans {
186+
if let Some(node) = nodes.get_mut(&branch_span.span.ctxt().outer_expn()) {
187+
node.branch_spans.push(BranchSpan::clone(branch_span));
188+
}
189+
}
190+
}
191+
153192
ExpnTree { nodes }
154193
}

compiler/rustc_mir_transform/src/coverage/mappings.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use rustc_middle::mir::coverage::{
44
};
55
use rustc_middle::mir::{self, BasicBlock, StatementKind};
66
use rustc_middle::ty::TyCtxt;
7+
use rustc_span::ExpnKind;
78

8-
use crate::coverage::expansion;
9+
use crate::coverage::expansion::{self, ExpnTree};
910
use crate::coverage::graph::CoverageGraph;
1011
use crate::coverage::hir_info::ExtractedHirInfo;
1112
use crate::coverage::spans::extract_refined_covspans;
12-
use crate::coverage::unexpand::unexpand_into_body_span;
1313

1414
#[derive(Default)]
1515
pub(crate) struct ExtractedMappings {
@@ -31,7 +31,7 @@ pub(crate) fn extract_mappings_from_mir<'tcx>(
3131
// Extract ordinary code mappings from MIR statement/terminator spans.
3232
extract_refined_covspans(tcx, hir_info, graph, &expn_tree, &mut mappings);
3333

34-
extract_branch_mappings(mir_body, hir_info, graph, &mut mappings);
34+
extract_branch_mappings(mir_body, hir_info, graph, &expn_tree, &mut mappings);
3535

3636
ExtractedMappings { mappings }
3737
}
@@ -57,25 +57,25 @@ fn resolve_block_markers(
5757
block_markers
5858
}
5959

60-
pub(super) fn extract_branch_mappings(
60+
fn extract_branch_mappings(
6161
mir_body: &mir::Body<'_>,
6262
hir_info: &ExtractedHirInfo,
6363
graph: &CoverageGraph,
64+
expn_tree: &ExpnTree,
6465
mappings: &mut Vec<Mapping>,
6566
) {
6667
let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return };
67-
6868
let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
6969

70-
mappings.extend(coverage_info_hi.branch_spans.iter().filter_map(
71-
|&BranchSpan { span: raw_span, true_marker, false_marker }| try {
72-
// For now, ignore any branch span that was introduced by
73-
// expansion. This makes things like assert macros less noisy.
74-
if !raw_span.ctxt().outer_expn_data().is_root() {
75-
return None;
76-
}
77-
let span = unexpand_into_body_span(raw_span, hir_info.body_span)?;
70+
// For now, ignore any branch span that was introduced by
71+
// expansion. This makes things like assert macros less noisy.
72+
let Some(node) = expn_tree.get(hir_info.body_span.ctxt().outer_expn()) else { return };
73+
if node.expn_kind != ExpnKind::Root {
74+
return;
75+
}
7876

77+
mappings.extend(node.branch_spans.iter().filter_map(
78+
|&BranchSpan { span, true_marker, false_marker }| try {
7979
let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?);
8080

8181
let true_bcb = bcb_from_marker(true_marker)?;

compiler/rustc_mir_transform/src/coverage/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ pub(super) mod query;
1717
mod spans;
1818
#[cfg(test)]
1919
mod tests;
20-
mod unexpand;
2120

2221
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
2322
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ pub(super) fn extract_refined_covspans<'tcx>(
2626
return;
2727
}
2828

29-
let &ExtractedHirInfo { body_span, .. } = hir_info;
30-
3129
// If there somehow isn't an expansion tree node corresponding to the
3230
// body span, return now and don't create any mappings.
33-
let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) else { return };
31+
let Some(node) = expn_tree.get(hir_info.body_span.ctxt().outer_expn()) else { return };
3432

3533
let mut covspans = vec![];
3634

@@ -47,27 +45,29 @@ pub(super) fn extract_refined_covspans<'tcx>(
4745
}
4846
}
4947

50-
covspans.retain(|covspan: &Covspan| {
51-
let covspan_span = covspan.span;
52-
// Discard any spans not contained within the function body span.
53-
// Also discard any spans that fill the entire body, because they tend
54-
// to represent compiler-inserted code, e.g. implicitly returning `()`.
55-
if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) {
56-
return false;
57-
}
48+
if let Some(body_span) = node.body_span {
49+
covspans.retain(|covspan: &Covspan| {
50+
let covspan_span = covspan.span;
51+
// Discard any spans not contained within the function body span.
52+
// Also discard any spans that fill the entire body, because they tend
53+
// to represent compiler-inserted code, e.g. implicitly returning `()`.
54+
if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) {
55+
return false;
56+
}
5857

59-
// Each pushed covspan should have the same context as the body span.
60-
// If it somehow doesn't, discard the covspan, or panic in debug builds.
61-
if !body_span.eq_ctxt(covspan_span) {
62-
debug_assert!(
63-
false,
64-
"span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}"
65-
);
66-
return false;
67-
}
58+
// Each pushed covspan should have the same context as the body span.
59+
// If it somehow doesn't, discard the covspan, or panic in debug builds.
60+
if !body_span.eq_ctxt(covspan_span) {
61+
debug_assert!(
62+
false,
63+
"span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}"
64+
);
65+
return false;
66+
}
6867

69-
true
70-
});
68+
true
69+
});
70+
}
7171

7272
// Only proceed if we found at least one usable span.
7373
if covspans.is_empty() {
@@ -78,10 +78,9 @@ pub(super) fn extract_refined_covspans<'tcx>(
7878
// Otherwise, add a fake span at the start of the body, to avoid an ugly
7979
// gap between the start of the body and the first real span.
8080
// FIXME: Find a more principled way to solve this problem.
81-
covspans.push(Covspan {
82-
span: hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()),
83-
bcb: START_BCB,
84-
});
81+
if let Some(span) = node.fn_sig_span.or_else(|| try { node.body_span?.shrink_to_lo() }) {
82+
covspans.push(Covspan { span, bcb: START_BCB });
83+
}
8584

8685
let compare_covspans = |a: &Covspan, b: &Covspan| {
8786
compare_spans(a.span, b.span)

compiler/rustc_mir_transform/src/coverage/unexpand.rs

Lines changed: 0 additions & 9 deletions
This file was deleted.

compiler/rustc_resolve/src/rustdoc.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,13 +393,15 @@ pub fn has_primitive_or_keyword_or_attribute_docs(attrs: &[impl AttributeExt]) -
393393
}
394394

395395
/// Simplified version of the corresponding function in rustdoc.
396-
/// If the rustdoc version returns a successful result, this function must return the same result.
397-
/// Otherwise this function may return anything.
398396
fn preprocess_link(link: &str) -> Box<str> {
397+
// IMPORTANT: To be kept in sync with the corresponding function in rustdoc.
398+
// Namely, whenever the rustdoc function returns a successful result for a given input,
399+
// this function *MUST* return a link that's equal to `PreprocessingInfo.path_str`!
400+
399401
let link = link.replace('`', "");
400402
let link = link.split('#').next().unwrap();
401403
let link = link.trim();
402-
let link = link.rsplit('@').next().unwrap();
404+
let link = link.split_once('@').map_or(link, |(_, rhs)| rhs);
403405
let link = link.trim_suffix("()");
404406
let link = link.trim_suffix("{}");
405407
let link = link.trim_suffix("[]");

library/std/src/thread/id.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ impl ThreadId {
7070

7171
// Acquire lock.
7272
let mut spin = 0;
73-
while COUNTER_LOCKED.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
73+
// Miri doesn't like it when we yield here as it interferes with deterministically
74+
// scheduling threads, so avoid `compare_exchange_weak` to avoid spurious yields.
75+
while COUNTER_LOCKED.swap(true, Ordering::Acquire, Ordering::Relaxed) {
7476
if spin <= 3 {
7577
for _ in 0..(1 << spin) {
7678
spin_loop();
@@ -80,6 +82,7 @@ impl ThreadId {
8082
}
8183
spin += 1;
8284
}
85+
// This was `false` before the swap, so we got the lock.
8386

8487
// SAFETY: we have an exclusive lock on the counter.
8588
unsafe {

src/librustdoc/passes/collect_intra_doc_links.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -901,14 +901,18 @@ pub(crate) struct PreprocessedMarkdownLink(
901901

902902
/// Returns:
903903
/// - `None` if the link should be ignored.
904-
/// - `Some(Err)` if the link should emit an error
905-
/// - `Some(Ok)` if the link is valid
904+
/// - `Some(Err(_))` if the link should emit an error
905+
/// - `Some(Ok(_))` if the link is valid
906906
///
907907
/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
908908
fn preprocess_link(
909909
ori_link: &MarkdownLink,
910910
dox: &str,
911911
) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
912+
// IMPORTANT: To be kept in sync with the corresponding function in `rustc_resolve::rustdoc`.
913+
// Namely, whenever this function returns a successful result for a given input,
914+
// the rustc counterpart *MUST* return a link that's equal to `PreprocessingInfo.path_str`!
915+
912916
// certain link kinds cannot have their path be urls,
913917
// so they should not be ignored, no matter how much they look like urls.
914918
// e.g. [https://example.com/] is not a link to example.com.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Function name: fn_in_macro::branch_in_macro
2+
Raw bytes (19): 0x[01, 01, 00, 03, 01, 22, 01, 00, 15, 01, 0b, 05, 00, 17, 01, 01, 01, 00, 02]
3+
Number of files: 1
4+
- file 0 => $DIR/fn-in-macro.rs
5+
Number of expressions: 0
6+
Number of file 0 mappings: 3
7+
- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 21)
8+
- Code(Counter(0)) at (prev + 11, 5) to (start + 0, 23)
9+
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
10+
Highest counter ID seen: c0
11+
12+
Function name: fn_in_macro::fn_in_macro
13+
Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0c, 09, 00, 19, 01, 01, 10, 00, 25, 05, 00, 2c, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
14+
Number of files: 1
15+
- file 0 => $DIR/fn-in-macro.rs
16+
Number of expressions: 1
17+
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
18+
Number of file 0 mappings: 5
19+
- Code(Counter(0)) at (prev + 12, 9) to (start + 0, 25)
20+
- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 37)
21+
- Code(Counter(1)) at (prev + 0, 44) to (start + 2, 14)
22+
- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
23+
= (c0 - c1)
24+
- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
25+
Highest counter ID seen: c1
26+
27+
Function name: fn_in_macro::fn_not_in_macro
28+
Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 19, 01, 00, 15, 01, 01, 08, 00, 1d, 20, 05, 02, 00, 08, 00, 23, 05, 00, 24, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
29+
Number of files: 1
30+
- file 0 => $DIR/fn-in-macro.rs
31+
Number of expressions: 1
32+
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
33+
Number of file 0 mappings: 6
34+
- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 21)
35+
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 29)
36+
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 35)
37+
true = c1
38+
false = (c0 - c1)
39+
- Code(Counter(1)) at (prev + 0, 36) to (start + 2, 6)
40+
- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
41+
= (c0 - c1)
42+
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
43+
Highest counter ID seen: c1
44+

0 commit comments

Comments
 (0)