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:
bors 2023-12-20 16:01:46 +00:00
commit 92ad4b433a
8 changed files with 151 additions and 42 deletions

View File

@ -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>(

View File

@ -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,

View File

@ -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
} }

View File

@ -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

View 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))

View 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| |}

View 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;
}
}
}
}