Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3c728ad

Browse files
committedApr 2, 2020
WIP - Add LLVM coverage instrumentation
#34701 Prototype coverage implementation with partial support for the various branch types to be covered. cargo -vv rustc -- -Z instrument-coverage With the `-Z instrument-coverage` flag, the compiler injects calls to a new std::coverage module, adding counters at various points in the code. At the end of the compile, a list of coverage regions (`Span`s) and corresponding coverage retion IDs are printed to stdout. When executing the program, the counters increment statically, and upon normal exit, the counters are printed to stdout with the same corresponding coverage region IDs. The stdout results will be replaced by output files in a format compatible with LLVM coverage reports. Currently counts the following coverage regions: * All blocks ending in a semicolon or expression * break, return, and yield statements, with or without a value expression * continue statment Not yet supported are: * match pattern arms without a block * closures without a block * expressions ending in '?' (that return on Result::Err) * lazy boolean right-hand-side expressions that may not be invoked
1 parent 7ff63c2 commit 3c728ad

File tree

11 files changed

+389
-354
lines changed

11 files changed

+389
-354
lines changed
 

‎Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3622,6 +3622,7 @@ dependencies = [
36223622
"rustc_ast",
36233623
"rustc_resolve",
36243624
"rustc_span",
3625+
"smallvec 1.0.0",
36253626
]
36263627

36273628
[[package]]

‎src/librustc_ast_lowering/lib.rs

-184
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ use rustc_ast::ast;
4040
use rustc_ast::ast::*;
4141
use rustc_ast::attr;
4242
use rustc_ast::node_id::NodeMap;
43-
use rustc_ast::ptr::P;
4443
use rustc_ast::token::{self, Nonterminal, Token};
4544
use rustc_ast::tokenstream::{TokenStream, TokenTree};
4645
use rustc_ast::visit::{self, AssocCtxt, Visitor};
@@ -70,7 +69,6 @@ use log::{debug, trace};
7069
use smallvec::{smallvec, SmallVec};
7170
use std::collections::BTreeMap;
7271
use std::mem;
73-
use std::sync::Mutex;
7472

7573
macro_rules! arena_vec {
7674
($this:expr; $($x:expr),*) => ({
@@ -173,9 +171,6 @@ struct LoweringContext<'a, 'hir: 'a> {
173171

174172
allow_try_trait: Option<Lrc<[Symbol]>>,
175173
allow_gen_future: Option<Lrc<[Symbol]>>,
176-
177-
/// `true` if `rustc` was invoked with an option to inject code coverage instrumentation.
178-
is_instrumenting_for_coverage: bool,
179174
}
180175

181176
pub trait Resolver {
@@ -305,7 +300,6 @@ pub fn lower_crate<'a, 'hir>(
305300
in_scope_lifetimes: Vec::new(),
306301
allow_try_trait: Some([sym::try_trait][..].into()),
307302
allow_gen_future: Some([sym::gen_future][..].into()),
308-
is_instrumenting_for_coverage: false,
309303
}
310304
.lower_crate(krate)
311305
}
@@ -400,148 +394,6 @@ impl Visitor<'_> for ImplTraitTypeIdVisitor<'_> {
400394
}
401395
}
402396

403-
struct CoverageRegion {
404-
region: Span,
405-
counter_hash: u128,
406-
}
407-
408-
static mut COVERAGE_REGIONS: Option<Mutex<Vec<CoverageRegion>>> = None;
409-
410-
impl CoverageRegion {
411-
412-
/// Generates a unique coverage region identifier to associate with
413-
/// a counter. The counter increment statement is injected into the
414-
/// code at the start of a coverage region.
415-
// TODO(richkadel): This function will need additional arguments and/or context
416-
// data from which to generate the hash values.
417-
fn generate_hash(region: &Span) -> u128 {
418-
// THIS IS NOT THREAD SAFE, BUT WILL BE REPLACED WITH HASH FUNCTION ANYWAY.
419-
// Seems like lazy_static is not used in the compiler at all.
420-
static mut NEXT_COUNTER_ID: Option<Mutex<u128>> = None;
421-
let counter_hash = {
422-
let counter_id = unsafe {
423-
&match NEXT_COUNTER_ID.as_ref() {
424-
Some(counter_id) => counter_id,
425-
None => {
426-
NEXT_COUNTER_ID = Some(Mutex::new(0));
427-
NEXT_COUNTER_ID.as_ref().unwrap()
428-
}
429-
}
430-
};
431-
let mut locked_counter_id = counter_id.lock().unwrap();
432-
*locked_counter_id += 1;
433-
*locked_counter_id
434-
};
435-
436-
let coverage_regions = unsafe {
437-
&match COVERAGE_REGIONS.as_ref() {
438-
Some(coverage_regions) => coverage_regions,
439-
None => {
440-
COVERAGE_REGIONS = Some(Mutex::new(vec![]));
441-
COVERAGE_REGIONS.as_ref().unwrap()
442-
}
443-
}
444-
};
445-
let mut locked_coverage_regions = coverage_regions.lock().unwrap();
446-
locked_coverage_regions.push(CoverageRegion {
447-
region: region.clone(),
448-
counter_hash,
449-
});
450-
451-
// return the counter hash value
452-
counter_hash
453-
}
454-
455-
pub fn write_coverage_regions(/* filename param? */) {
456-
unsafe {
457-
if let Some(coverage_regions) = COVERAGE_REGIONS.as_ref() {
458-
let locked_coverage_regions = coverage_regions.lock().unwrap();
459-
for coverage in locked_coverage_regions.iter() {
460-
println!("{}: {:?}", coverage.counter_hash, coverage.region);
461-
}
462-
}
463-
}
464-
}
465-
}
466-
467-
struct CoverageInjector<'tcx, 'lowering, 'hir> {
468-
lctx: &'tcx mut LoweringContext<'lowering, 'hir>,
469-
span: Span,
470-
}
471-
472-
impl<'tcx, 'lowering, 'hir> CoverageInjector<'tcx, 'lowering, 'hir> {
473-
fn at(lctx: &'tcx mut LoweringContext<'lowering, 'hir>, before: &Span) -> CoverageInjector<'tcx, 'lowering, 'hir> {
474-
CoverageInjector {
475-
lctx,
476-
span: before.shrink_to_lo(),
477-
}
478-
}
479-
480-
fn next_ast_node_id(&mut self) -> NodeId {
481-
self.lctx.resolver.next_node_id()
482-
}
483-
484-
fn span(&self) -> Span {
485-
self.span.clone()
486-
}
487-
488-
fn expr(&mut self, kind: ExprKind) -> P<Expr> {
489-
P(Expr {
490-
kind,
491-
span: self.span(),
492-
attrs: AttrVec::new(),
493-
id: self.next_ast_node_id(),
494-
})
495-
}
496-
497-
fn path_segment(&mut self, string: &str) -> PathSegment {
498-
PathSegment {
499-
ident: Ident::from_str_and_span(string, self.span()),
500-
id: self.next_ast_node_id(),
501-
args: None,
502-
}
503-
}
504-
505-
fn coverage_count_fn_path(&mut self) -> P<Expr> {
506-
let path = Path {
507-
span: self.span(),
508-
segments: vec![
509-
self.path_segment("coverage"),
510-
self.path_segment("count"),
511-
],
512-
};
513-
self.expr(ExprKind::Path(None, path))
514-
}
515-
516-
fn coverage_counter_hash_lit(&mut self, counter_hash: u128) -> P<Expr> {
517-
let token = token::Lit::new(token::Integer, sym::integer(counter_hash), /*suffix=*/None);
518-
let kind = LitKind::Int(
519-
counter_hash,
520-
LitIntType::Unsigned(UintTy::U128), // TODO: this should not be necessary (should be "Unsuffixed" per JSON)
521-
);
522-
let lit = Lit { token, kind, span: self.span() };
523-
self.expr(ExprKind::Lit(lit))
524-
}
525-
526-
fn call(&mut self, fn_path: P<Expr>, args: Vec<P<Expr>>) -> P<Expr> {
527-
self.expr(ExprKind::Call(fn_path, args))
528-
}
529-
530-
fn counter_stmt(&mut self, coverage_span: &Span) -> Stmt {
531-
let counter_hash = CoverageRegion::generate_hash(coverage_span);
532-
let coverage_count_fn = self.coverage_count_fn_path();
533-
let args = vec![ self.coverage_counter_hash_lit(counter_hash) ];
534-
let call = self.call(coverage_count_fn, args);
535-
536-
Stmt {
537-
id: self.next_ast_node_id(),
538-
span: self.span(),
539-
kind: StmtKind::Semi(call)
540-
}
541-
}
542-
}
543-
544-
545397
impl<'a, 'hir> LoweringContext<'a, 'hir> {
546398
fn lower_crate(mut self, c: &Crate) -> hir::Crate<'hir> {
547399
/// Full-crate AST visitor that inserts into a fresh
@@ -669,21 +521,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
669521
}
670522
}
671523

672-
self.is_instrumenting_for_coverage = match self.sess.opts.debugging_opts.instrument_coverage {
673-
Some(opt) => opt,
674-
None => false,
675-
};
676-
677524
self.lower_node_id(CRATE_NODE_ID);
678525
debug_assert!(self.node_id_to_hir_id[CRATE_NODE_ID] == hir::CRATE_HIR_ID);
679526

680527
visit::walk_crate(&mut MiscCollector { lctx: &mut self, hir_id_owner: None }, c);
681528
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
682529

683-
if self.is_instrumenting_for_coverage {
684-
CoverageRegion::write_coverage_regions();
685-
}
686-
687530
let module = self.lower_mod(&c.module);
688531
let attrs = self.lower_attrs(&c.attrs);
689532
let body_ids = body_ids(&self.bodies);
@@ -2365,33 +2208,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23652208
let mut stmts = vec![];
23662209
let mut expr: Option<&'hir _> = None;
23672210

2368-
// THIS COVERAGE CODE MAY NEED TO BE IN A DIFFERENT LOCATION? BUT SEEMS LIKE IT SHOULD
2369-
// WORK FOR BASIC BLOCKS THAT DON'T `break`, `continue`, or `return` in any nested
2370-
// branches. For those, we need to add additional counters beyond the code that might be
2371-
// skipped.
2372-
if self.is_instrumenting_for_coverage && ! b.stmts.is_empty() {
2373-
let inject_site = &b.stmts[0].span;
2374-
let mut coverage_injector = CoverageInjector::at(self, inject_site);
2375-
let counter_stmt = coverage_injector.counter_stmt(&b.span);
2376-
stmts.extend(self.lower_stmt(&counter_stmt));
2377-
// TODO(richkadel): The span should stop at the first occurrence of an early return
2378-
// (if any), and if there is one, a new counter should be inserted just after the branch
2379-
// that ended in the early return, and a new span should start from just after that
2380-
// injected counter, and ending at the end of the block, or at another early return if
2381-
// there is another.
2382-
2383-
// ALSO! There are language constructs that have statement spans that don't require
2384-
// braces if only one statement, in which case, they PROBABLY don't hit "Block", and
2385-
// therefore, I need to insert the counters in other parts of the AST as well, while
2386-
// also virtually inserting the curly braces:
2387-
// * closures: |...| stmt -> |...| { coverage::counter(n); stmt }
2388-
// * match arms: match variant { pat => stmt, -> match variant { pat => coverage::counter(n); stmt }
2389-
// any others?
2390-
2391-
// There may be existing checks of similar types. See for instance "targeted_by_break"
2392-
// in this file.
2393-
}
2394-
23952211
for (index, stmt) in b.stmts.iter().enumerate() {
23962212
if index == b.stmts.len() - 1 {
23972213
if let StmtKind::Expr(ref e) = stmt.kind {

‎src/librustc_coverage/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ log = "0.4"
1313
rustc = { path = "../librustc" }
1414
rustc_resolve = { path = "../librustc_resolve" }
1515
rustc_ast = { path = "../librustc_ast" }
16-
rustc_span = { path = "../librustc_span" }
16+
rustc_span = { path = "../librustc_span" }
17+
smallvec = { version = "1.0", features = ["union", "may_dangle"] }

‎src/librustc_coverage/coverage.rs

+201-90
Large diffs are not rendered by default.

‎src/librustc_coverage/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
#![feature(nll)]
33
#![recursion_limit = "256"]
44

5-
pub mod coverage;
5+
pub mod coverage;

‎src/librustc_driver/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ use rustc_session::{early_error, early_warn};
4646
use rustc_span::source_map::{FileLoader, FileName};
4747
use rustc_span::symbol::sym;
4848

49-
use log::debug;
5049
use std::borrow::Cow;
5150
use std::cmp::max;
5251
use std::default::Default;
@@ -338,9 +337,7 @@ pub fn run_compiler(
338337
}
339338
}
340339

341-
debug!("before death");
342340
queries.expansion()?;
343-
debug!("AFTER DEATH (we don't get here?)");
344341
if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
345342
return early_exit();
346343
}

‎src/librustc_interface/passes.rs

+51-14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_ast::mut_visit::MutVisitor;
1515
use rustc_ast::{self, ast, visit};
1616
use rustc_codegen_ssa::back::link::emit_metadata;
1717
use rustc_codegen_ssa::traits::CodegenBackend;
18+
use rustc_coverage::coverage;
1819
use rustc_data_structures::sync::{par_iter, Lrc, Once, ParallelIterator, WorkerLocal};
1920
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
2021
use rustc_errors::PResult;
@@ -93,8 +94,8 @@ declare_box_region_type!(
9394

9495
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
9596
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
96-
/// harness if one is to be provided, injection of a dependency on the
97-
/// standard library and prelude, and name resolution.
97+
/// harness if one is to be provided, and injection of a dependency on the
98+
/// standard library and prelude.
9899
///
99100
/// Returns `None` if we're aborting after handling -W help.
100101
pub fn configure_and_expand(
@@ -137,6 +138,43 @@ pub fn configure_and_expand(
137138
result.map(|k| (k, resolver))
138139
}
139140

141+
/// If enabled by command line option, this pass injects coverage statements into the AST to
142+
/// increment region counters and generate a coverage report at program exit.
143+
/// The AST Crate cannot be resolved until after the AST is instrumented.
144+
pub fn instrument(krate: ast::Crate, resolver: &mut Resolver<'_>) -> Result<ast::Crate> {
145+
coverage::instrument(krate, resolver)
146+
}
147+
148+
/// Performs name resolution on the expanded and optionally instrumented crate.
149+
pub fn resolve_crate(
150+
sess: Lrc<Session>,
151+
krate: ast::Crate,
152+
resolver: &mut Resolver<'_>,
153+
) -> Result<ast::Crate> {
154+
let sess = &*sess;
155+
156+
resolver.resolve_crate(&krate);
157+
158+
// FIXME(richkadel): Run tests and confirm that check_crate must go after resolve_crate(),
159+
// and if not, can/should I move it into configure_and_expand_inner() (which would mean
160+
// running this before instrumentation, if that's OK).
161+
162+
// FIXME(richkadel): original comment here with small modification:
163+
164+
// Needs to go *after* expansion and name resolution, to be able to check the results of macro
165+
// expansion.
166+
sess.time("complete_gated_feature_checking", || {
167+
rustc_ast_passes::feature_gate::check_crate(
168+
&krate,
169+
&sess.parse_sess,
170+
&sess.features_untracked(),
171+
sess.opts.unstable_features,
172+
);
173+
});
174+
175+
Ok(krate)
176+
}
177+
140178
impl BoxedResolver {
141179
pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
142180
match Rc::try_unwrap(resolver) {
@@ -405,21 +443,10 @@ fn configure_and_expand_inner<'a>(
405443
}
406444

407445
if sess.opts.debugging_opts.ast_json {
446+
// Note this version of the AST will not include injected code, such as coverage counters.
408447
println!("{}", json::as_json(&krate));
409448
}
410449

411-
resolver.resolve_crate(&krate);
412-
413-
// Needs to go *after* expansion to be able to check the results of macro expansion.
414-
sess.time("complete_gated_feature_checking", || {
415-
rustc_ast_passes::feature_gate::check_crate(
416-
&krate,
417-
&sess.parse_sess,
418-
&sess.features_untracked(),
419-
sess.opts.unstable_features,
420-
);
421-
});
422-
423450
// Add all buffered lints from the `ParseSess` to the `Session`.
424451
sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
425452
info!("{} parse sess buffered_lints", buffered_lints.len());
@@ -428,6 +455,16 @@ fn configure_and_expand_inner<'a>(
428455
}
429456
});
430457

458+
// // Needs to go *after* expansion, to be able to check the results of macro expansion.
459+
// sess.time("complete_gated_feature_checking", || {
460+
// rustc_ast_passes::feature_gate::check_crate(
461+
// &krate,
462+
// &sess.parse_sess,
463+
// &sess.features_untracked(),
464+
// sess.opts.unstable_features,
465+
// );
466+
// });
467+
431468
Ok((krate, resolver))
432469
}
433470

‎src/librustc_interface/queries.rs

+49-60
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use rustc::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
88
use rustc::util::common::ErrorReported;
99
use rustc_ast::{self, ast};
1010
use rustc_codegen_ssa::traits::CodegenBackend;
11-
use rustc_coverage::coverage;
1211
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
1312
use rustc_hir::def_id::LOCAL_CRATE;
1413
use rustc_hir::Crate;
@@ -18,7 +17,6 @@ use rustc_session::config::{OutputFilenames, OutputType};
1817
use rustc_session::{output::find_crate_name, Session};
1918
use rustc_span::symbol::sym;
2019

21-
use log::debug;
2220
use std::any::Any;
2321
use std::cell::{Ref, RefCell, RefMut};
2422
use std::mem;
@@ -77,8 +75,9 @@ pub struct Queries<'tcx> {
7775
parse: Query<ast::Crate>,
7876
crate_name: Query<String>,
7977
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
80-
expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
78+
unresolved_expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
8179
instrument: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
80+
expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
8281
dep_graph: Query<DepGraph>,
8382
lower_to_hir: Query<(&'tcx Crate<'tcx>, Steal<ResolverOutputs>)>,
8483
prepare_outputs: Query<OutputFilenames>,
@@ -97,6 +96,7 @@ impl<'tcx> Queries<'tcx> {
9796
parse: Default::default(),
9897
crate_name: Default::default(),
9998
register_plugins: Default::default(),
99+
unresolved_expansion: Default::default(),
100100
expansion: Default::default(),
101101
instrument: Default::default(),
102102
dep_graph: Default::default(),
@@ -115,9 +115,7 @@ impl<'tcx> Queries<'tcx> {
115115
}
116116

117117
pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
118-
debug!("query dep_graph_future");
119118
self.dep_graph_future.compute(|| {
120-
debug!("compute query dep_graph_future");
121119
Ok(self
122120
.session()
123121
.opts
@@ -127,9 +125,7 @@ impl<'tcx> Queries<'tcx> {
127125
}
128126

129127
pub fn parse(&self) -> Result<&Query<ast::Crate>> {
130-
debug!("query parse");
131128
self.parse.compute(|| {
132-
debug!("compute query parse");
133129
passes::parse(self.session(), &self.compiler.input).map_err(|mut parse_error| {
134130
parse_error.emit();
135131
ErrorReported
@@ -138,9 +134,7 @@ impl<'tcx> Queries<'tcx> {
138134
}
139135

140136
pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
141-
debug!("query register_plugins");
142137
self.register_plugins.compute(|| {
143-
debug!("compute query register_plugins");
144138
let crate_name = self.crate_name()?.peek().clone();
145139
let krate = self.parse()?.take();
146140

@@ -165,9 +159,7 @@ impl<'tcx> Queries<'tcx> {
165159
}
166160

167161
pub fn crate_name(&self) -> Result<&Query<String>> {
168-
debug!("query crate_name");
169162
self.crate_name.compute(|| {
170-
debug!("compute query crate_name");
171163
Ok(match self.compiler.crate_name {
172164
Some(ref crate_name) => crate_name.clone(),
173165
None => {
@@ -179,16 +171,15 @@ impl<'tcx> Queries<'tcx> {
179171
})
180172
}
181173

182-
pub fn expansion(
174+
/// Expands built-ins and other macros, but does not perform name resolution, pending potential
175+
/// instrumentation.
176+
pub fn unresolved_expansion(
183177
&self,
184178
) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
185-
debug!("query expansion");
186-
self.expansion.compute(|| {
187-
debug!("compute query expansion");
179+
self.unresolved_expansion.compute(|| {
188180
let crate_name = self.crate_name()?.peek().clone();
189181
let (krate, lint_store) = self.register_plugins()?.take();
190182
let _timer = self.session().timer("configure_and_expand");
191-
debug!("just before death");
192183
passes::configure_and_expand(
193184
self.session().clone(),
194185
lint_store.clone(),
@@ -197,16 +188,53 @@ debug!("just before death");
197188
&crate_name,
198189
)
199190
.map(|(krate, resolver)| {
200-
debug!("NEVER GET HERE");
201191
(krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store)
202192
})
203193
})
204194
}
205195

196+
/// Returns a modified ast::Crate with injected instrumentation code, if requested by command
197+
/// line option.
198+
///
199+
/// The `instrument` pass/query depends on (and implies) `unresolved_expansion`.
200+
pub fn instrument(
201+
&self,
202+
) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
203+
self.instrument.compute(|| {
204+
let (krate, boxed_resolver, lint_store) = self.unresolved_expansion()?.take();
205+
let instrument_coverage = match self.session().opts.debugging_opts.instrument_coverage {
206+
Some(opt) => opt,
207+
None => false,
208+
};
209+
if instrument_coverage {
210+
boxed_resolver.borrow().borrow_mut().access(|resolver| {
211+
let _timer = self.session().timer("instrument_coverage");
212+
passes::instrument(krate, resolver)
213+
})
214+
} else {
215+
Ok(krate)
216+
}
217+
.map(|krate| (krate, boxed_resolver, lint_store))
218+
})
219+
}
220+
221+
/// Updates the ast::Crate, first querying `instrument`, which queries `unresolved_expansion`.
222+
/// After all expansions and instrumentation, performs name resolution on the final AST.
223+
pub fn expansion(
224+
&self,
225+
) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
226+
self.expansion.compute(|| {
227+
let (krate, boxed_resolver, lint_store) = self.instrument()?.take();
228+
let result = boxed_resolver.borrow().borrow_mut().access(|resolver| {
229+
let _timer = self.session().timer("resolve_expansion");
230+
passes::resolve_crate(self.session().clone(), krate, resolver)
231+
});
232+
result.map(|krate| (krate, boxed_resolver, lint_store))
233+
})
234+
}
235+
206236
pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
207-
debug!("query dep_graph");
208237
self.dep_graph.compute(|| {
209-
debug!("compute query dep_graph");
210238
Ok(match self.dep_graph_future()?.take() {
211239
None => DepGraph::new_disabled(),
212240
Some(future) => {
@@ -225,42 +253,10 @@ debug!("NEVER GET HERE");
225253
})
226254
}
227255

228-
/// Instrumentation is optional (typically included based on `rustc` option). The
229-
/// `instrument` pass/query depends on (and implies) `expansion`. To ensure the instrumentation
230-
/// pass is executed (if requested), replace queries to `expansion` with queries to
231-
/// `instrument`. The query results are the same. If instrumentation is not requested,
232-
/// `expansion` will be queried and returned. If instrumentation is requested, `instrument`
233-
/// will query `expansion`, inject instrumentation code (modifying the crate and updating the
234-
/// `next_node_id()` in the resolver), and then return the query result from `expansion`, with
235-
/// the changes to crate and resolver.
236-
pub fn instrument(&'tcx self) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
237-
debug!("query instrument (depends on expansion), will instrument coverage if requested");
238-
let expansion = self.expansion();
239-
let instrument_coverage = match self.session().opts.debugging_opts.instrument_coverage {
240-
Some(opt) => opt,
241-
None => false,
242-
};
243-
if instrument_coverage {
244-
self.instrument.compute(|| {
245-
debug!("compute query instrument (depends on expansion), will instrument coverage if requested");
246-
let (mut krate, boxed_resolver, lint_store) = expansion?.take();
247-
let resolver = boxed_resolver.steal();
248-
resolver.borrow_mut().access(|resolver| {
249-
coverage::instrument(&mut krate, resolver)
250-
});
251-
Ok((krate, Steal::new(resolver), lint_store))
252-
})
253-
} else {
254-
expansion
255-
}
256-
}
257-
258256
pub fn lower_to_hir(&'tcx self) -> Result<&Query<(&'tcx Crate<'tcx>, Steal<ResolverOutputs>)>> {
259-
debug!("query lower_to_hir");
260257
self.lower_to_hir.compute(|| {
261-
debug!("compute query lower_to_hir");
262-
let instrument_result = self.instrument()?;
263-
let peeked = instrument_result.peek();
258+
let expansion_result = self.expansion()?;
259+
let peeked = expansion_result.peek();
264260
let krate = &peeked.0;
265261
let resolver = peeked.1.steal();
266262
let lint_store = &peeked.2;
@@ -280,9 +276,7 @@ debug!("NEVER GET HERE");
280276
}
281277

282278
pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
283-
debug!("query prepare_outputs");
284279
self.prepare_outputs.compute(|| {
285-
debug!("compute query prepare_outputs");
286280
let expansion_result = self.expansion()?;
287281
let (krate, boxed_resolver, _) = &*expansion_result.peek();
288282
let crate_name = self.crate_name()?;
@@ -298,9 +292,7 @@ debug!("NEVER GET HERE");
298292
}
299293

300294
pub fn global_ctxt(&'tcx self) -> Result<&Query<QueryContext<'tcx>>> {
301-
debug!("query global_ctxt");
302295
self.global_ctxt.compute(|| {
303-
debug!("compute query global_ctxt");
304296
let crate_name = self.crate_name()?.peek().clone();
305297
let outputs = self.prepare_outputs()?.peek().clone();
306298
let lint_store = self.expansion()?.peek().2.clone();
@@ -323,9 +315,7 @@ debug!("NEVER GET HERE");
323315
}
324316

325317
pub fn ongoing_codegen(&'tcx self) -> Result<&Query<Box<dyn Any>>> {
326-
debug!("query ongoing_codegen");
327318
self.ongoing_codegen.compute(|| {
328-
debug!("compute query ongoing_codegen");
329319
let outputs = self.prepare_outputs()?;
330320
self.global_ctxt()?.peek_mut().enter(|tcx| {
331321
tcx.analysis(LOCAL_CRATE).ok();
@@ -413,7 +403,6 @@ pub struct Linker {
413403

414404
impl Linker {
415405
pub fn link(self) -> Result<()> {
416-
debug!("Linker::link");
417406
let codegen_results =
418407
self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess, &self.dep_graph)?;
419408
let prof = self.sess.prof.clone();

‎src/librustc_session/session.rs

-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,6 @@ impl Session {
440440
}
441441

442442
pub fn init_features(&self, features: rustc_feature::Features) {
443-
debug!("ABOUT TO PANIC?")
444443
self.features.set(features);
445444
}
446445

‎src/libstd/coverage.rs

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//! Code coverage counters and report
2+
//!
3+
//! The code coverage library is typically not included in Rust source files.
4+
//!
5+
//! Instead, the `rustc` compiler optionally injects coverage calls into the internal representation
6+
//! of the source if requested by command line option to the compiler. The end result is an
7+
//! executable that includes the coverage counters, and writes a coverage report upon exit.
8+
//!
9+
//! The injected calls behave as if code like the following examples was actually part of the
10+
//! original source.
11+
//!
12+
//! Example:
13+
//!
14+
//! ```
15+
//! main() {
16+
//! let value = if (true) {
17+
//! std::coverage::count(1, {
18+
//! // any expression
19+
//! 1000
20+
//! })
21+
//! } else {
22+
//! std::coverage::count(2, 500)
23+
//! }
24+
//! std::coverage::count_and_report(3, ())
25+
//! }
26+
//! ```
27+
28+
#![stable(feature = "coverage", since = "1.44.0")]
29+
30+
use crate::collections::HashMap;
31+
use crate::sync::LockResult;
32+
use crate::sync::Mutex;
33+
use crate::sync::MutexGuard;
34+
use crate::sync::Once;
35+
36+
static mut COUNTERS: Option<Mutex<HashMap<u128, usize>>> = None;
37+
38+
static INIT: Once = Once::new();
39+
40+
#[stable(feature = "coverage", since = "1.44.0")]
41+
#[inline]
42+
fn increment_counter(counter: u128) -> LockResult<MutexGuard<'static, HashMap<u128, usize>>> {
43+
let mut lock = unsafe {
44+
INIT.call_once(|| {
45+
COUNTERS = Some(Mutex::new(HashMap::with_capacity(1024)));
46+
});
47+
COUNTERS.as_mut().unwrap().lock()
48+
};
49+
let counters = lock.as_mut().unwrap();
50+
match counters.get_mut(&counter) {
51+
Some(count) => *count += 1,
52+
None => {
53+
counters.insert(counter, 1);
54+
}
55+
}
56+
lock
57+
}
58+
59+
/// The statement may be the last statement of a block, the value of a `return` or `break`,
60+
/// a match pattern arm statement that might not be in a block (but if it is, don't wrap both the
61+
/// block and the last statement of the block), or a closure statement without braces.
62+
///
63+
/// coverage::count(234234, {some_statement_with_or_without_semicolon()})
64+
#[stable(feature = "coverage", since = "1.44.0")]
65+
#[inline]
66+
pub fn count<T>(counter: u128, result: T) -> T {
67+
let _ = increment_counter(counter);
68+
result
69+
}
70+
71+
/// Increment the specified counter and then write the coverage report. This function normally wraps
72+
/// the final expression in a `main()` function. There can be more than one statement, for example
73+
/// if the `main()` has one or more `return` statements. In this case, all returns and the last
74+
/// statement of `main()` (unless not reachable) should use this function.
75+
#[stable(feature = "coverage", since = "1.44.0")]
76+
pub fn count_and_report<T>(counter: u128, result: T) -> T {
77+
println!("Print the coverage counters:");
78+
let mut counters = increment_counter(counter).unwrap();
79+
for (counter, count) in counters.drain() {
80+
println!("Counter '{}' has count: {}", counter, count);
81+
}
82+
result
83+
}

‎src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ pub mod thread;
447447
pub mod ascii;
448448
pub mod backtrace;
449449
pub mod collections;
450+
pub mod coverage;
450451
pub mod env;
451452
pub mod error;
452453
pub mod ffi;

0 commit comments

Comments
 (0)
Please sign in to comment.