From bd984ddcc18d0ff1fb35e3a2491c91cb4187d4a1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 Dec 2023 13:21:04 +0100 Subject: [PATCH 1/6] Update documentation for `--env` compilation flag --- .../unstable-book/src/compiler-flags/env.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/compiler-flags/env.md b/src/doc/unstable-book/src/compiler-flags/env.md index df0547dd24b..56f804fcd0c 100644 --- a/src/doc/unstable-book/src/compiler-flags/env.md +++ b/src/doc/unstable-book/src/compiler-flags/env.md @@ -5,7 +5,10 @@ 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 -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. 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: @@ -20,6 +23,21 @@ Then you will have: 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 preserving whereas `rustc`'s environment variables are case sensitive. For example, having `Path` in your environment (case insensitive) is different than using From 4ae792036e2207aff742df30ab1955b1a6cb97e2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 19 Dec 2023 22:17:10 +1100 Subject: [PATCH 2/6] coverage: Add a test for `async` blocks We have coverage tests that use async functions, but none that use async blocks. --- tests/coverage/async_block.cov-map | 32 +++++++++++++++++++++++++ tests/coverage/async_block.coverage | 37 +++++++++++++++++++++++++++++ tests/coverage/async_block.rs | 35 +++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 tests/coverage/async_block.cov-map create mode 100644 tests/coverage/async_block.coverage create mode 100644 tests/coverage/async_block.rs diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map new file mode 100644 index 00000000000..104133f6e67 --- /dev/null +++ b/tests/coverage/async_block.cov-map @@ -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)) + diff --git a/tests/coverage/async_block.coverage b/tests/coverage/async_block.coverage new file mode 100644 index 00000000000..297397ca26c --- /dev/null +++ b/tests/coverage/async_block.coverage @@ -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(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| |} + diff --git a/tests/coverage/async_block.rs b/tests/coverage/async_block.rs new file mode 100644 index 00000000000..9d8647bf1f2 --- /dev/null +++ b/tests/coverage/async_block.rs @@ -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(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; + } + } + } +} From 2a0290a8025b668b9e86c59379cfb8a8a9d91813 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 19 Dec 2023 21:50:13 +1100 Subject: [PATCH 3/6] coverage: Pass around `&ExtractedHirInfo` instead of individual fields This reduces the risk of mixing up `fn_source_span` and `body_span`, and makes it easier to pass along additional fields as needed. --- .../rustc_mir_transform/src/coverage/mod.rs | 24 +++++-------------- .../rustc_mir_transform/src/coverage/spans.rs | 15 +++++------- .../src/coverage/spans/from_mir.rs | 6 +++-- 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 709d1fdc21a..3bd5b7f2b85 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -68,32 +68,21 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { struct Instrumentor<'a, 'tcx> { tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>, - fn_sig_span: Span, - body_span: Span, - function_source_hash: u64, + hir_info: ExtractedHirInfo, basic_coverage_blocks: CoverageGraph, coverage_counters: CoverageCounters, } impl<'a, 'tcx> Instrumentor<'a, 'tcx> { 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 } = - extract_hir_info(tcx, mir_body.source.def_id().expect_local()); + let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local()); debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id()); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); let coverage_counters = CoverageCounters::new(&basic_coverage_blocks); - Self { - tcx, - mir_body, - fn_sig_span, - body_span, - function_source_hash, - basic_coverage_blocks, - coverage_counters, - } + Self { tcx, mir_body, hir_info, basic_coverage_blocks, coverage_counters } } fn inject_counters(&'a mut self) { @@ -101,8 +90,7 @@ fn inject_counters(&'a mut self) { // Compute coverage spans from the `CoverageGraph`. let Some(coverage_spans) = CoverageSpans::generate_coverage_spans( self.mir_body, - self.fn_sig_span, - self.body_span, + &self.hir_info, &self.basic_coverage_blocks, ) else { // 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); 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(), expressions: self.coverage_counters.take_expressions(), mappings, @@ -136,7 +124,7 @@ fn create_mappings_and_inject_coverage_statements( coverage_spans: &CoverageSpans, ) -> Vec { 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()); use rustc_session::RemapFileNameExt; diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 462e54c386c..ae43a18ad4e 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -6,6 +6,7 @@ use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP}; use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; +use crate::coverage::ExtractedHirInfo; mod from_mir; @@ -21,14 +22,12 @@ impl CoverageSpans { /// Returns `None` if no coverage-relevant spans could be extracted. pub(super) fn generate_coverage_spans( mir_body: &mir::Body<'_>, - fn_sig_span: Span, - body_span: Span, + hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> Option { let coverage_spans = CoverageSpansGenerator::generate_coverage_spans( mir_body, - fn_sig_span, - body_span, + hir_info, basic_coverage_blocks, ); @@ -230,19 +229,17 @@ impl<'a> CoverageSpansGenerator<'a> { /// to be). pub(super) fn generate_coverage_spans( mir_body: &mir::Body<'_>, - fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span` - body_span: Span, + hir_info: &ExtractedHirInfo, basic_coverage_blocks: &'a CoverageGraph, ) -> Vec { let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans( mir_body, - fn_sig_span, - body_span, + hir_info, basic_coverage_blocks, ); let coverage_spans = Self { - body_span, + body_span: hir_info.body_span, basic_coverage_blocks, sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, 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 eab9a9c98f8..da460da3588 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -7,13 +7,15 @@ use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use crate::coverage::spans::CoverageSpan; +use crate::coverage::ExtractedHirInfo; pub(super) fn mir_to_initial_sorted_coverage_spans( mir_body: &mir::Body<'_>, - fn_sig_span: Span, - body_span: Span, + hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> Vec { + let &ExtractedHirInfo { fn_sig_span, body_span, .. } = hir_info; + let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2); 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)); From cf6dc7adb3b9e9fc67f947bfffb75f852883b050 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 19 Dec 2023 22:05:34 +1100 Subject: [PATCH 4/6] coverage: Check for `async fn` explicitly, without needing a heuristic The old code used a heuristic to detect async functions and adjust their coverage spans to produce better output. But there's no need to resort to a heuristic when we can just check whether the current function is actually an `async fn`. --- .../rustc_mir_transform/src/coverage/mod.rs | 4 +++- .../src/coverage/spans/from_mir.rs | 19 ++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 3bd5b7f2b85..c5a3391286a 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -299,6 +299,7 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { #[derive(Debug)] struct ExtractedHirInfo { function_source_hash: u64, + is_async_fn: bool, fn_sig_span: Span, body_span: Span, } @@ -312,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"); 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); // The actual signature span is only used if it has the same context and @@ -333,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); - 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>( 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 da460da3588..a9c4ea33d0e 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -14,7 +14,14 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> Vec { - let &ExtractedHirInfo { fn_sig_span, body_span, .. } = hir_info; + 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); for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { @@ -46,16 +53,6 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( .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 } From 8468840a563176b866478bfbcfc0642c47bc501d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 20 Dec 2023 14:00:22 +0300 Subject: [PATCH 5/6] Update LLVM submodule to pick up "[M68k] Fix ODR violation in GISel code (#72797)" https://github.com/rust-lang/llvm-project/pull/159 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 2c4de6c2492..606bc11367b 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 2c4de6c2492d5530de3f19f41d8f88ba984c2fe2 +Subproject commit 606bc11367b475542bd6228163424ca43b4dbdbc From 2679bca97aaefd76c4969fc879f510294f9976f0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Dec 2023 15:37:45 +0100 Subject: [PATCH 6/6] Add link to explanations about dep-info files --- src/doc/unstable-book/src/compiler-flags/env.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/compiler-flags/env.md b/src/doc/unstable-book/src/compiler-flags/env.md index 56f804fcd0c..ac6d7474a9b 100644 --- a/src/doc/unstable-book/src/compiler-flags/env.md +++ b/src/doc/unstable-book/src/compiler-flags/env.md @@ -8,7 +8,8 @@ This option flag allows to specify environment variables value at compile time t 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. +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 precedence. For example, if you want have `PATH=a` in your environment and pass: