Auto merge of #119166 - GuillaumeGomez:rollup-qfgj76w, r=GuillaumeGomez
Rollup of 3 pull requests Successful merges: - #119115 (Update documentation for `--env` compilation flag) - #119155 (coverage: Check for `async fn` explicitly, without needing a heuristic) - #119159 (Update LLVM submodule) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
92ad4b433a
@ -68,32 +68,21 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
|
|||||||
struct Instrumentor<'a, 'tcx> {
|
struct Instrumentor<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
mir_body: &'a mut mir::Body<'tcx>,
|
mir_body: &'a mut mir::Body<'tcx>,
|
||||||
fn_sig_span: Span,
|
hir_info: ExtractedHirInfo,
|
||||||
body_span: Span,
|
|
||||||
function_source_hash: u64,
|
|
||||||
basic_coverage_blocks: CoverageGraph,
|
basic_coverage_blocks: CoverageGraph,
|
||||||
coverage_counters: CoverageCounters,
|
coverage_counters: CoverageCounters,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||||
fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
|
fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
|
||||||
let hir_info @ ExtractedHirInfo { function_source_hash, fn_sig_span, body_span } =
|
let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local());
|
||||||
extract_hir_info(tcx, mir_body.source.def_id().expect_local());
|
|
||||||
|
|
||||||
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
|
debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
|
||||||
|
|
||||||
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
|
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
|
||||||
let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
|
let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
|
||||||
|
|
||||||
Self {
|
Self { tcx, mir_body, hir_info, basic_coverage_blocks, coverage_counters }
|
||||||
tcx,
|
|
||||||
mir_body,
|
|
||||||
fn_sig_span,
|
|
||||||
body_span,
|
|
||||||
function_source_hash,
|
|
||||||
basic_coverage_blocks,
|
|
||||||
coverage_counters,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_counters(&'a mut self) {
|
fn inject_counters(&'a mut self) {
|
||||||
@ -101,8 +90,7 @@ fn inject_counters(&'a mut self) {
|
|||||||
// Compute coverage spans from the `CoverageGraph`.
|
// Compute coverage spans from the `CoverageGraph`.
|
||||||
let Some(coverage_spans) = CoverageSpans::generate_coverage_spans(
|
let Some(coverage_spans) = CoverageSpans::generate_coverage_spans(
|
||||||
self.mir_body,
|
self.mir_body,
|
||||||
self.fn_sig_span,
|
&self.hir_info,
|
||||||
self.body_span,
|
|
||||||
&self.basic_coverage_blocks,
|
&self.basic_coverage_blocks,
|
||||||
) else {
|
) else {
|
||||||
// No relevant spans were found in MIR, so skip instrumenting this function.
|
// No relevant spans were found in MIR, so skip instrumenting this function.
|
||||||
@ -121,7 +109,7 @@ fn inject_counters(&'a mut self) {
|
|||||||
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
|
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
|
||||||
|
|
||||||
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
||||||
function_source_hash: self.function_source_hash,
|
function_source_hash: self.hir_info.function_source_hash,
|
||||||
num_counters: self.coverage_counters.num_counters(),
|
num_counters: self.coverage_counters.num_counters(),
|
||||||
expressions: self.coverage_counters.take_expressions(),
|
expressions: self.coverage_counters.take_expressions(),
|
||||||
mappings,
|
mappings,
|
||||||
@ -136,7 +124,7 @@ fn create_mappings_and_inject_coverage_statements(
|
|||||||
coverage_spans: &CoverageSpans,
|
coverage_spans: &CoverageSpans,
|
||||||
) -> Vec<Mapping> {
|
) -> Vec<Mapping> {
|
||||||
let source_map = self.tcx.sess.source_map();
|
let source_map = self.tcx.sess.source_map();
|
||||||
let body_span = self.body_span;
|
let body_span = self.hir_info.body_span;
|
||||||
|
|
||||||
let source_file = source_map.lookup_source_file(body_span.lo());
|
let source_file = source_map.lookup_source_file(body_span.lo());
|
||||||
use rustc_session::RemapFileNameExt;
|
use rustc_session::RemapFileNameExt;
|
||||||
@ -311,6 +299,7 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ExtractedHirInfo {
|
struct ExtractedHirInfo {
|
||||||
function_source_hash: u64,
|
function_source_hash: u64,
|
||||||
|
is_async_fn: bool,
|
||||||
fn_sig_span: Span,
|
fn_sig_span: Span,
|
||||||
body_span: Span,
|
body_span: Span,
|
||||||
}
|
}
|
||||||
@ -324,6 +313,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
|
|||||||
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
|
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
|
||||||
let hir_body = tcx.hir().body(fn_body_id);
|
let hir_body = tcx.hir().body(fn_body_id);
|
||||||
|
|
||||||
|
let is_async_fn = hir_node.fn_sig().is_some_and(|fn_sig| fn_sig.header.is_async());
|
||||||
let body_span = get_body_span(tcx, hir_body, def_id);
|
let body_span = get_body_span(tcx, hir_body, def_id);
|
||||||
|
|
||||||
// The actual signature span is only used if it has the same context and
|
// The actual signature span is only used if it has the same context and
|
||||||
@ -345,7 +335,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
|
|||||||
|
|
||||||
let function_source_hash = hash_mir_source(tcx, hir_body);
|
let function_source_hash = hash_mir_source(tcx, hir_body);
|
||||||
|
|
||||||
ExtractedHirInfo { function_source_hash, fn_sig_span, body_span }
|
ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_body_span<'tcx>(
|
fn get_body_span<'tcx>(
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
|
use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
|
||||||
|
|
||||||
use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
|
use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
|
||||||
|
use crate::coverage::ExtractedHirInfo;
|
||||||
|
|
||||||
mod from_mir;
|
mod from_mir;
|
||||||
|
|
||||||
@ -21,14 +22,12 @@ impl CoverageSpans {
|
|||||||
/// Returns `None` if no coverage-relevant spans could be extracted.
|
/// Returns `None` if no coverage-relevant spans could be extracted.
|
||||||
pub(super) fn generate_coverage_spans(
|
pub(super) fn generate_coverage_spans(
|
||||||
mir_body: &mir::Body<'_>,
|
mir_body: &mir::Body<'_>,
|
||||||
fn_sig_span: Span,
|
hir_info: &ExtractedHirInfo,
|
||||||
body_span: Span,
|
|
||||||
basic_coverage_blocks: &CoverageGraph,
|
basic_coverage_blocks: &CoverageGraph,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let coverage_spans = CoverageSpansGenerator::generate_coverage_spans(
|
let coverage_spans = CoverageSpansGenerator::generate_coverage_spans(
|
||||||
mir_body,
|
mir_body,
|
||||||
fn_sig_span,
|
hir_info,
|
||||||
body_span,
|
|
||||||
basic_coverage_blocks,
|
basic_coverage_blocks,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -230,19 +229,17 @@ impl<'a> CoverageSpansGenerator<'a> {
|
|||||||
/// to be).
|
/// to be).
|
||||||
pub(super) fn generate_coverage_spans(
|
pub(super) fn generate_coverage_spans(
|
||||||
mir_body: &mir::Body<'_>,
|
mir_body: &mir::Body<'_>,
|
||||||
fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span`
|
hir_info: &ExtractedHirInfo,
|
||||||
body_span: Span,
|
|
||||||
basic_coverage_blocks: &'a CoverageGraph,
|
basic_coverage_blocks: &'a CoverageGraph,
|
||||||
) -> Vec<CoverageSpan> {
|
) -> Vec<CoverageSpan> {
|
||||||
let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
|
let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
|
||||||
mir_body,
|
mir_body,
|
||||||
fn_sig_span,
|
hir_info,
|
||||||
body_span,
|
|
||||||
basic_coverage_blocks,
|
basic_coverage_blocks,
|
||||||
);
|
);
|
||||||
|
|
||||||
let coverage_spans = Self {
|
let coverage_spans = Self {
|
||||||
body_span,
|
body_span: hir_info.body_span,
|
||||||
basic_coverage_blocks,
|
basic_coverage_blocks,
|
||||||
sorted_spans_iter: sorted_spans.into_iter(),
|
sorted_spans_iter: sorted_spans.into_iter(),
|
||||||
some_curr: None,
|
some_curr: None,
|
||||||
|
@ -7,13 +7,22 @@
|
|||||||
|
|
||||||
use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
|
use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
|
||||||
use crate::coverage::spans::CoverageSpan;
|
use crate::coverage::spans::CoverageSpan;
|
||||||
|
use crate::coverage::ExtractedHirInfo;
|
||||||
|
|
||||||
pub(super) fn mir_to_initial_sorted_coverage_spans(
|
pub(super) fn mir_to_initial_sorted_coverage_spans(
|
||||||
mir_body: &mir::Body<'_>,
|
mir_body: &mir::Body<'_>,
|
||||||
fn_sig_span: Span,
|
hir_info: &ExtractedHirInfo,
|
||||||
body_span: Span,
|
|
||||||
basic_coverage_blocks: &CoverageGraph,
|
basic_coverage_blocks: &CoverageGraph,
|
||||||
) -> Vec<CoverageSpan> {
|
) -> Vec<CoverageSpan> {
|
||||||
|
let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info;
|
||||||
|
if is_async_fn {
|
||||||
|
// An async function desugars into a function that returns a future,
|
||||||
|
// with the user code wrapped in a closure. Any spans in the desugared
|
||||||
|
// outer function will be unhelpful, so just produce a single span
|
||||||
|
// associating the function signature with its entry BCB.
|
||||||
|
return vec![CoverageSpan::for_fn_sig(fn_sig_span)];
|
||||||
|
}
|
||||||
|
|
||||||
let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2);
|
let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2);
|
||||||
for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
|
for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
|
||||||
initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data));
|
initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data));
|
||||||
@ -44,16 +53,6 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
|
|||||||
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
|
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
|
||||||
});
|
});
|
||||||
|
|
||||||
// The desugaring of an async function includes a closure containing the
|
|
||||||
// original function body, and a terminator that returns the `impl Future`.
|
|
||||||
// That terminator will cause a confusing coverage count for the function's
|
|
||||||
// closing brace, so discard everything after the body closure span.
|
|
||||||
if let Some(body_closure_index) =
|
|
||||||
initial_spans.iter().rposition(|covspan| covspan.is_closure && covspan.span == body_span)
|
|
||||||
{
|
|
||||||
initial_spans.truncate(body_closure_index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
initial_spans
|
initial_spans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,11 @@ The tracking issue for this feature is: [#118372](https://github.com/rust-lang/r
|
|||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
This option flag allows to specify environment variables value at compile time to be
|
This option flag allows to specify environment variables value at compile time to be
|
||||||
used by `env!` and `option_env!` macros.
|
used by `env!` and `option_env!` macros. It also impacts `tracked_env::var` function
|
||||||
|
from the `proc_macro` crate.
|
||||||
|
|
||||||
|
This information will be stored in the dep-info files. For more information about
|
||||||
|
dep-info files, take a look [here](https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files).
|
||||||
|
|
||||||
When retrieving an environment variable value, the one specified by `--env` will take
|
When retrieving an environment variable value, the one specified by `--env` will take
|
||||||
precedence. For example, if you want have `PATH=a` in your environment and pass:
|
precedence. For example, if you want have `PATH=a` in your environment and pass:
|
||||||
@ -20,6 +24,21 @@ Then you will have:
|
|||||||
assert_eq!(env!("PATH"), "env");
|
assert_eq!(env!("PATH"), "env");
|
||||||
```
|
```
|
||||||
|
|
||||||
|
It will trigger a new compilation if any of the `--env` argument value is different.
|
||||||
|
So if you first passed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
--env A=B --env X=12
|
||||||
|
```
|
||||||
|
|
||||||
|
and then on next compilation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
--env A=B
|
||||||
|
```
|
||||||
|
|
||||||
|
`X` value is different (not set) so the code will be re-compiled.
|
||||||
|
|
||||||
Please note that on Windows, environment variables are case insensitive but case
|
Please note that on Windows, environment variables are case insensitive but case
|
||||||
preserving whereas `rustc`'s environment variables are case sensitive. For example,
|
preserving whereas `rustc`'s environment variables are case sensitive. For example,
|
||||||
having `Path` in your environment (case insensitive) is different than using
|
having `Path` in your environment (case insensitive) is different than using
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 2c4de6c2492d5530de3f19f41d8f88ba984c2fe2
|
Subproject commit 606bc11367b475542bd6228163424ca43b4dbdbc
|
32
tests/coverage/async_block.cov-map
Normal file
32
tests/coverage/async_block.cov-map
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
Function name: async_block::main
|
||||||
|
Raw bytes (38): 0x[01, 01, 02, 01, 05, 03, 05, 06, 01, 05, 01, 00, 0b, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 13, 05, 00, 14, 01, 16, 05, 07, 0a, 02, 06, 06, 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 = Expression(0, Add), rhs = Counter(1)
|
||||||
|
Number of file 0 mappings: 6
|
||||||
|
- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 11)
|
||||||
|
- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10)
|
||||||
|
- Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 19)
|
||||||
|
= (c0 + c1)
|
||||||
|
- Code(Counter(1)) at (prev + 0, 20) to (start + 1, 22)
|
||||||
|
- Code(Counter(1)) at (prev + 7, 10) to (start + 2, 6)
|
||||||
|
- Code(Expression(1, Sub)) at (prev + 3, 1) to (start + 0, 2)
|
||||||
|
= ((c0 + c1) - c1)
|
||||||
|
|
||||||
|
Function name: async_block::main::{closure#0}
|
||||||
|
Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 07, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
|
||||||
|
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: 4
|
||||||
|
- Code(Counter(0)) at (prev + 7, 28) to (start + 1, 23)
|
||||||
|
- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
|
||||||
|
- Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
|
||||||
|
= (c0 - c1)
|
||||||
|
- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
|
||||||
|
= (c1 + (c0 - c1))
|
||||||
|
|
37
tests/coverage/async_block.coverage
Normal file
37
tests/coverage/async_block.coverage
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
LL| |#![feature(coverage_attribute)]
|
||||||
|
LL| |#![feature(noop_waker)]
|
||||||
|
LL| |// edition: 2021
|
||||||
|
LL| |
|
||||||
|
LL| 1|fn main() {
|
||||||
|
LL| 17| for i in 0..16 {
|
||||||
|
^16
|
||||||
|
LL| 16| let future = async {
|
||||||
|
LL| 16| if i >= 12 {
|
||||||
|
LL| 4| println!("big");
|
||||||
|
LL| 12| } else {
|
||||||
|
LL| 12| println!("small");
|
||||||
|
LL| 12| }
|
||||||
|
LL| 16| };
|
||||||
|
LL| 16| executor::block_on(future);
|
||||||
|
LL| 16| }
|
||||||
|
LL| 1|}
|
||||||
|
LL| |
|
||||||
|
LL| |mod executor {
|
||||||
|
LL| | use core::future::Future;
|
||||||
|
LL| | use core::pin::pin;
|
||||||
|
LL| | use core::task::{Context, Poll, Waker};
|
||||||
|
LL| |
|
||||||
|
LL| | #[coverage(off)]
|
||||||
|
LL| | pub fn block_on<F: Future>(mut future: F) -> F::Output {
|
||||||
|
LL| | let mut future = pin!(future);
|
||||||
|
LL| | let waker = Waker::noop();
|
||||||
|
LL| | let mut context = Context::from_waker(&waker);
|
||||||
|
LL| |
|
||||||
|
LL| | loop {
|
||||||
|
LL| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
|
||||||
|
LL| | break val;
|
||||||
|
LL| | }
|
||||||
|
LL| | }
|
||||||
|
LL| | }
|
||||||
|
LL| |}
|
||||||
|
|
35
tests/coverage/async_block.rs
Normal file
35
tests/coverage/async_block.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#![feature(coverage_attribute)]
|
||||||
|
#![feature(noop_waker)]
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
for i in 0..16 {
|
||||||
|
let future = async {
|
||||||
|
if i >= 12 {
|
||||||
|
println!("big");
|
||||||
|
} else {
|
||||||
|
println!("small");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
executor::block_on(future);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod executor {
|
||||||
|
use core::future::Future;
|
||||||
|
use core::pin::pin;
|
||||||
|
use core::task::{Context, Poll, Waker};
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
pub fn block_on<F: Future>(mut future: F) -> F::Output {
|
||||||
|
let mut future = pin!(future);
|
||||||
|
let waker = Waker::noop();
|
||||||
|
let mut context = Context::from_waker(&waker);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
|
||||||
|
break val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user