diff --git a/Cargo.lock b/Cargo.lock index 9cca91c25df0a..97d07cd6ca8ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2223,12 +2223,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437" -dependencies = [ - "clap", -] +checksum = "bd559bbf5d350ac7f2c1cf92ed71a869b847a92bce0c1318b47932a5b5f65cdd" [[package]] name = "minimal-lexical" diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index feac97f3e2b62..a6e07ea2a60ec 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -1,5 +1,7 @@ use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion}; +use crate::coverageinfo::mapgen::LocalFileId; + /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] @@ -137,8 +139,12 @@ pub(crate) struct CoverageSpan { } impl CoverageSpan { - pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self { - let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region; + pub(crate) fn from_source_region( + local_file_id: LocalFileId, + code_region: &SourceRegion, + ) -> Self { + let file_id = local_file_id.as_u32(); + let &SourceRegion { start_line, start_col, end_line, end_col } = code_region; // Internally, LLVM uses the high bit of `end_col` to distinguish between // code regions and gap regions, so it can't be used by the column number. assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}"); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index 5ed640b840e76..e3c0df278836e 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -6,7 +6,6 @@ use rustc_middle::mir::coverage::{ SourceRegion, }; use rustc_middle::ty::Instance; -use rustc_span::Symbol; use tracing::{debug, instrument}; use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; @@ -180,7 +179,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> { } pub(crate) struct FunctionCoverage<'tcx> { - function_coverage_info: &'tcx FunctionCoverageInfo, + pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo, is_used: bool, counters_seen: BitSet, @@ -199,11 +198,6 @@ impl<'tcx> FunctionCoverage<'tcx> { if self.is_used { self.function_coverage_info.function_source_hash } else { 0 } } - /// Returns an iterator over all filenames used by this function's mappings. - pub(crate) fn all_file_names(&self) -> impl Iterator + Captures<'_> { - self.function_coverage_info.mappings.iter().map(|mapping| mapping.source_region.file_name) - } - /// Convert this function's coverage expression data into a form that can be /// passed through FFI to LLVM. pub(crate) fn counter_expressions( diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index bb2f634cb2592..b582dd967a706 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -12,8 +12,10 @@ use rustc_index::IndexVec; use rustc_middle::mir::coverage::MappingKind; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; -use rustc_span::Symbol; +use rustc_session::RemapFileNameExt; +use rustc_session::config::RemapPathScopeComponents; use rustc_span::def_id::DefIdSet; +use rustc_span::{Span, Symbol}; use rustc_target::spec::HasTargetSpec; use tracing::debug; @@ -70,8 +72,10 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { .map(|(instance, function_coverage)| (instance, function_coverage.into_finished())) .collect::>(); - let all_file_names = - function_coverage_entries.iter().flat_map(|(_, fn_cov)| fn_cov.all_file_names()); + let all_file_names = function_coverage_entries + .iter() + .map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span) + .map(|span| span_file_name(tcx, span)); let global_file_table = GlobalFileTable::new(all_file_names); // Encode all filenames referenced by coverage mappings in this CGU. @@ -96,7 +100,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { let is_used = function_coverage.is_used(); let coverage_mapping_buffer = - encode_mappings_for_function(&global_file_table, &function_coverage); + encode_mappings_for_function(tcx, &global_file_table, &function_coverage); if coverage_mapping_buffer.is_empty() { if function_coverage.is_used() { @@ -164,13 +168,13 @@ impl GlobalFileTable { Self { raw_file_table } } - fn global_file_id_for_file_name(&self, file_name: Symbol) -> u32 { + fn global_file_id_for_file_name(&self, file_name: Symbol) -> GlobalFileId { let raw_id = self.raw_file_table.get_index_of(&file_name).unwrap_or_else(|| { bug!("file name not found in prepared global file table: {file_name}"); }); // The raw file table doesn't include an entry for the working dir // (which has ID 0), so add 1 to get the correct ID. - (raw_id + 1) as u32 + GlobalFileId::from_usize(raw_id + 1) } fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec { @@ -196,19 +200,27 @@ impl GlobalFileTable { } rustc_index::newtype_index! { - struct LocalFileId {} + /// An index into the CGU's overall list of file paths. The underlying paths + /// will be embedded in the `__llvm_covmap` linker section. + struct GlobalFileId {} +} +rustc_index::newtype_index! { + /// An index into a function's list of global file IDs. That underlying list + /// of local-to-global mappings will be embedded in the function's record in + /// the `__llvm_covfun` linker section. + pub(crate) struct LocalFileId {} } /// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU) /// file IDs. #[derive(Default)] struct VirtualFileMapping { - local_to_global: IndexVec, - global_to_local: FxIndexMap, + local_to_global: IndexVec, + global_to_local: FxIndexMap, } impl VirtualFileMapping { - fn local_id_for_global(&mut self, global_file_id: u32) -> LocalFileId { + fn local_id_for_global(&mut self, global_file_id: GlobalFileId) -> LocalFileId { *self .global_to_local .entry(global_file_id) @@ -216,16 +228,26 @@ impl VirtualFileMapping { } fn into_vec(self) -> Vec { - self.local_to_global.raw + // This conversion should be optimized away to ~zero overhead. + // In any case, it's probably not hot enough to worry about. + self.local_to_global.into_iter().map(|global| global.as_u32()).collect() } } +fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol { + let source_file = tcx.sess.source_map().lookup_source_file(span.lo()); + let name = + source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(); + Symbol::intern(&name) +} + /// Using the expressions and counter regions collected for a single function, /// generate the variable-sized payload of its corresponding `__llvm_covfun` /// entry. The payload is returned as a vector of bytes. /// /// Newly-encountered filenames will be added to the global file table. fn encode_mappings_for_function( + tcx: TyCtxt<'_>, global_file_table: &GlobalFileTable, function_coverage: &FunctionCoverage<'_>, ) -> Vec { @@ -242,53 +264,45 @@ fn encode_mappings_for_function( let mut mcdc_branch_regions = vec![]; let mut mcdc_decision_regions = vec![]; - // Group mappings into runs with the same filename, preserving the order - // yielded by `FunctionCoverage`. - // Prepare file IDs for each filename, and prepare the mapping data so that - // we can pass it through FFI to LLVM. - for (file_name, counter_regions_for_file) in - &counter_regions.group_by(|(_, region)| region.file_name) - { - // Look up the global file ID for this filename. - let global_file_id = global_file_table.global_file_id_for_file_name(file_name); - - // Associate that global file ID with a local file ID for this function. - let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id); - debug!(" file id: {local_file_id:?} => global {global_file_id} = '{file_name:?}'"); - - // For each counter/region pair in this function+file, convert it to a - // form suitable for FFI. - for (mapping_kind, region) in counter_regions_for_file { - debug!("Adding counter {mapping_kind:?} to map for {region:?}"); - let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region); - match mapping_kind { - MappingKind::Code(term) => { - code_regions - .push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); - } - MappingKind::Branch { true_term, false_term } => { - branch_regions.push(ffi::BranchRegion { - span, - true_counter: ffi::Counter::from_term(true_term), - false_counter: ffi::Counter::from_term(false_term), - }); - } - MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { - mcdc_branch_regions.push(ffi::MCDCBranchRegion { - span, - true_counter: ffi::Counter::from_term(true_term), - false_counter: ffi::Counter::from_term(false_term), - mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), - }); - } - MappingKind::MCDCDecision(mcdc_decision_params) => { - mcdc_decision_regions.push(ffi::MCDCDecisionRegion { - span, - mcdc_decision_params: ffi::mcdc::DecisionParameters::from( - mcdc_decision_params, - ), - }); - } + // Currently a function's mappings must all be in the same file as its body span. + let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span); + + // Look up the global file ID for that filename. + let global_file_id = global_file_table.global_file_id_for_file_name(file_name); + + // Associate that global file ID with a local file ID for this function. + let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id); + debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'"); + + // For each counter/region pair in this function+file, convert it to a + // form suitable for FFI. + for (mapping_kind, region) in counter_regions { + debug!("Adding counter {mapping_kind:?} to map for {region:?}"); + let span = ffi::CoverageSpan::from_source_region(local_file_id, region); + match mapping_kind { + MappingKind::Code(term) => { + code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); + } + MappingKind::Branch { true_term, false_term } => { + branch_regions.push(ffi::BranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + }); + } + MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { + mcdc_branch_regions.push(ffi::MCDCBranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), + }); + } + MappingKind::MCDCDecision(mcdc_decision_params) => { + mcdc_decision_regions.push(ffi::MCDCDecisionRegion { + span, + mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params), + }); } } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 4a876dc1228e5..11a4e7f89a7c7 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter}; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; rustc_index::newtype_index! { /// Used by [`CoverageKind::BlockMarker`] to mark blocks during THIR-to-MIR @@ -158,7 +158,6 @@ impl Debug for CoverageKind { #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)] #[derive(TypeFoldable, TypeVisitable)] pub struct SourceRegion { - pub file_name: Symbol, pub start_line: u32, pub start_col: u32, pub end_line: u32, @@ -167,11 +166,8 @@ pub struct SourceRegion { impl Debug for SourceRegion { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - write!( - fmt, - "{}:{}:{} - {}:{}", - self.file_name, self.start_line, self.start_col, self.end_line, self.end_col - ) + let &Self { start_line, start_col, end_line, end_col } = self; + write!(fmt, "{start_line}:{start_col} - {end_line}:{end_col}") } } @@ -246,6 +242,7 @@ pub struct Mapping { #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct FunctionCoverageInfo { pub function_source_hash: u64, + pub body_span: Span, pub num_counters: usize, pub mcdc_bitmap_bits: usize, pub expressions: IndexVec, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index d0f93c19e44e6..f0e2b7a376cd3 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -596,8 +596,10 @@ fn write_function_coverage_info( function_coverage_info: &coverage::FunctionCoverageInfo, w: &mut dyn io::Write, ) -> io::Result<()> { - let coverage::FunctionCoverageInfo { expressions, mappings, .. } = function_coverage_info; + let coverage::FunctionCoverageInfo { body_span, expressions, mappings, .. } = + function_coverage_info; + writeln!(w, "{INDENT}coverage body span: {body_span:?}")?; for (id, expression) in expressions.iter_enumerated() { writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?; } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 2e4c503f3ce5b..e8b3d80be0212 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -22,8 +22,8 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; -use tracing::{debug, debug_span, instrument, trace}; +use rustc_span::{BytePos, Pos, SourceFile, Span}; +use tracing::{debug, debug_span, trace}; use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; use crate::coverage::graph::CoverageGraph; @@ -122,6 +122,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, + body_span: hir_info.body_span, num_counters: coverage_counters.num_counters(), mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits, expressions: coverage_counters.into_expressions(), @@ -142,19 +143,11 @@ fn create_mappings<'tcx>( coverage_counters: &CoverageCounters, ) -> Vec { let source_map = tcx.sess.source_map(); - let body_span = hir_info.body_span; - - let source_file = source_map.lookup_source_file(body_span.lo()); - - use rustc_session::RemapFileNameExt; - use rustc_session::config::RemapPathScopeComponents; - let file_name = Symbol::intern( - &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), - ); + let file = source_map.lookup_source_file(hir_info.body_span.lo()); let term_for_bcb = |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters"); - let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span); + let region_for_span = |span: Span| make_source_region(source_map, hir_info, &file, span); // Fully destructure the mappings struct to make sure we don't miss any kinds. let ExtractedMappings { @@ -398,7 +391,42 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb data.statements.insert(0, statement); } -/// Convert the Span into its file name, start line and column, and end line and column. +fn ensure_non_empty_span( + source_map: &SourceMap, + hir_info: &ExtractedHirInfo, + span: Span, +) -> Option { + if !span.is_empty() { + return Some(span); + } + + let lo = span.lo(); + let hi = span.hi(); + + // The span is empty, so try to expand it to cover an adjacent '{' or '}', + // but only within the bounds of the body span. + let try_next = hi < hir_info.body_span.hi(); + let try_prev = hir_info.body_span.lo() < lo; + if !(try_next || try_prev) { + return None; + } + + source_map + .span_to_source(span, |src, start, end| try { + // We're only checking for specific ASCII characters, so we don't + // have to worry about multi-byte code points. + if try_next && src.as_bytes()[end] == b'{' { + Some(span.with_hi(hi + BytePos(1))) + } else if try_prev && src.as_bytes()[start - 1] == b'}' { + Some(span.with_lo(lo - BytePos(1))) + } else { + None + } + }) + .ok()? +} + +/// Converts the span into its start line and column, and end line and column. /// /// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by /// the compiler, these column numbers are denoted in **bytes**, because that's what @@ -408,56 +436,29 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb /// but it's hard to rule out entirely (especially in the presence of complex macros /// or other expansions), and if it does happen then skipping a span or function is /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. -#[instrument(level = "debug", skip(source_map))] fn make_source_region( source_map: &SourceMap, - file_name: Symbol, + hir_info: &ExtractedHirInfo, + file: &SourceFile, span: Span, - body_span: Span, ) -> Option { + let span = ensure_non_empty_span(source_map, hir_info, span)?; + let lo = span.lo(); let hi = span.hi(); - let file = source_map.lookup_source_file(lo); - if !file.contains(hi) { - debug!(?span, ?file, ?lo, ?hi, "span crosses multiple files; skipping"); - return None; - } - // Column numbers need to be in bytes, so we can't use the more convenient // `SourceMap` methods for looking up file coordinates. - let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> { + let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> { let rpos = file.relative_position(pos); let line_index = file.lookup_line(rpos)?; let line_start = file.lines()[line_index]; // Line numbers and column numbers are 1-based, so add 1 to each. - Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1)) + Some((line_index + 1, (rpos - line_start).to_usize() + 1)) }; - let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?; - let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?; - - // If the span is empty, try to expand it horizontally by one character's - // worth of bytes, so that it is more visible in `llvm-cov` reports. - // We do this after resolving line/column numbers, so that empty spans at the - // end of a line get an extra column instead of wrapping to the next line. - if span.is_empty() - && body_span.contains(span) - && let Some(src) = &file.src - { - // Prefer to expand the end position, if it won't go outside the body span. - if hi < body_span.hi() { - let hi_rpos = hi_rpos.to_usize(); - let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos; - end_col += nudge_bytes; - } else if lo > body_span.lo() { - let lo_rpos = lo_rpos.to_usize(); - let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1); - // Subtract the nudge, but don't go below column 1. - start_col = start_col.saturating_sub(nudge_bytes).max(1); - } - // If neither nudge could be applied, stick with the empty span coordinates. - } + let (mut start_line, start_col) = line_and_byte_column(lo)?; + let (mut end_line, end_col) = line_and_byte_column(hi)?; // Apply an offset so that code in doctests has correct line numbers. // FIXME(#79417): Currently we have no way to offset doctest _columns_. @@ -465,7 +466,6 @@ fn make_source_region( end_line = source_map.doctest_offset_line(&file.name, end_line); check_source_region(SourceRegion { - file_name, start_line: start_line as u32, start_col: start_col as u32, end_line: end_line as u32, @@ -478,7 +478,7 @@ fn make_source_region( /// discard regions that are improperly ordered, or might be interpreted in a /// way that makes them improperly ordered. fn check_source_region(source_region: SourceRegion) -> Option { - let SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = source_region; + let SourceRegion { start_line, start_col, end_line, end_col } = source_region; // Line/column coordinates are supposed to be 1-based. If we ever emit // coordinates of 0, `llvm-cov` might misinterpret them. diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index d184328748f84..e18f66ac0a3bb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -9,7 +9,6 @@ #![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] -#![feature(round_char_boundary)] #![feature(try_blocks)] #![feature(yeet_expr)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f36bb38623e5d..e74a5c2d8fe75 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -534,7 +534,7 @@ impl SourceMap { /// Extracts the source surrounding the given `Span` using the `extract_source` function. The /// extract function takes three arguments: a string slice containing the source, an index in /// the slice for the beginning of the span and an index in the slice for the end of the span. - fn span_to_source(&self, sp: Span, extract_source: F) -> Result + pub fn span_to_source(&self, sp: Span, extract_source: F) -> Result where F: Fn(&str, usize, usize) -> Result, { diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 57b6de67ee8a9..70749f7cb17a0 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -13,7 +13,7 @@ rinja = { version = "0.3", default-features = false, features = ["config"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" -minifier = "0.3.1" +minifier = { version = "0.3.2", default-features = false } pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 2e49131982297..209fd622202e2 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -58,11 +58,20 @@ jobs: - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items + coverage: + name: coverage report + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/workflows/setup + - name: coverage + run: ./miri test --coverage + # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! # And they should be added below in `cron-fail-notify` as well. conclusion: - needs: [build, style] + needs: [build, style, coverage] # We need to ensure this job does *not* get skipped if its dependencies fail, # because a skipped job is considered a success by GitHub. So we have to # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run @@ -86,7 +95,7 @@ jobs: contents: write # ... and create a PR. pull-requests: write - needs: [build, style] + needs: [build, style, coverage] if: ${{ github.event_name == 'schedule' && failure() }} steps: # Send a Zulip notification diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index d0bcf68eacb19..e97f4bf86d834 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -13,6 +13,25 @@ for a list of Miri maintainers. [Rust Zulip]: https://rust-lang.zulipchat.com +### Pull review process + +When you get a review, please take care of the requested changes in new commits. Do not amend +existing commits. Generally avoid force-pushing. The only time you should force push is when there +is a conflict with the master branch (in that case you should rebase across master, not merge), and +all the way at the end of the review process when the reviewer tells you that the PR is done and you +should squash the commits. For the latter case, use `git rebase --keep-base ...` to squash without +changing the base commit your PR branches off of. Use your own judgment and the reviewer's guidance +to decide whether the PR should be squashed into a single commit or multiple logically separate +commits. (All this is to work around the fact that Github is quite bad at dealing with force pushes +and does not support `git range-diff`. Maybe one day Github will be good at git and then life can +become easier.) + +Most PRs bounce back and forth between the reviewer and the author several times, so it is good to +keep track of who is expected to take the next step. We are using the `S-waiting-for-review` and +`S-waiting-for-author` labels for that. If a reviewer asked you to do some changes and you think +they are all taken care of, post a comment saying `@rustbot ready` to mark a PR as ready for the +next round of review. + ### Larger-scale contributions If you are thinking about making a larger-scale contribution -- in particular anything that needs @@ -45,14 +64,6 @@ process for such contributions: This process is largely informal, and its primary goal is to more clearly communicate expectations. Please get in touch with us if you have any questions! -### Managing the review state - -Most PRs bounce back and forth between the reviewer and the author several times, so it is good to -keep track of who is expected to take the next step. We are using the `S-waiting-for-review` and -`S-waiting-for-author` labels for that. If a reviewer asked you to do some changes and you think -they are all taken care of, post a comment saying `@rustbot ready` to mark a PR as ready for the -next round of review. - ## Preparing the build environment Miri heavily relies on internal and unstable rustc interfaces to execute MIR, diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 4e7cbc50ca03b..0356d7ecf1015 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -154,7 +154,7 @@ case $HOST_TARGET in TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe - TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap threadname pthread + TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync threadname pthread TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std diff --git a/src/tools/miri/clippy.toml b/src/tools/miri/clippy.toml index c11912d6e68ce..504be47459c23 100644 --- a/src/tools/miri/clippy.toml +++ b/src/tools/miri/clippy.toml @@ -1 +1 @@ -arithmetic-side-effects-allowed = ["rustc_abi::Size"] +arithmetic-side-effects-allowed = ["rustc_abi::Size", "rustc_apfloat::ieee::IeeeFloat"] diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock index 146e613c24b36..8dad30df6d1e6 100644 --- a/src/tools/miri/miri-script/Cargo.lock +++ b/src/tools/miri/miri-script/Cargo.lock @@ -63,6 +63,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + [[package]] name = "getrandom" version = "0.2.12" @@ -100,9 +106,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libredox" @@ -138,11 +144,18 @@ dependencies = [ "rustc_version", "serde_json", "shell-words", + "tempfile", "walkdir", "which", "xshell", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "option-ext" version = "0.2.0" @@ -195,9 +208,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags", "errno", @@ -276,6 +289,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" version = "1.0.57" @@ -357,6 +383,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml index 23b9a62515920..5b31d5a6ff97b 100644 --- a/src/tools/miri/miri-script/Cargo.toml +++ b/src/tools/miri/miri-script/Cargo.toml @@ -24,3 +24,4 @@ rustc_version = "0.4" dunce = "1.0.4" directories = "5" serde_json = "1" +tempfile = "3.13.0" diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 36175c8dd2bd2..21029d0b5b3db 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -172,7 +172,8 @@ impl Command { Command::Install { flags } => Self::install(flags), Command::Build { flags } => Self::build(flags), Command::Check { flags } => Self::check(flags), - Command::Test { bless, flags, target } => Self::test(bless, flags, target), + Command::Test { bless, flags, target, coverage } => + Self::test(bless, flags, target, coverage), Command::Run { dep, verbose, many_seeds, target, edition, flags } => Self::run(dep, verbose, many_seeds, target, edition, flags), Command::Doc { flags } => Self::doc(flags), @@ -458,9 +459,20 @@ impl Command { Ok(()) } - fn test(bless: bool, mut flags: Vec, target: Option) -> Result<()> { + fn test( + bless: bool, + mut flags: Vec, + target: Option, + coverage: bool, + ) -> Result<()> { let mut e = MiriEnv::new()?; + let coverage = coverage.then_some(crate::coverage::CoverageReport::new()?); + + if let Some(report) = &coverage { + report.add_env_vars(&mut e)?; + } + // Prepare a sysroot. (Also builds cargo-miri, which we need.) e.build_miri_sysroot(/* quiet */ false, target.as_deref())?; @@ -479,6 +491,11 @@ impl Command { // Then test, and let caller control flags. // Only in root project as `cargo-miri` has no tests. e.test(".", &flags)?; + + if let Some(coverage) = &coverage { + coverage.show_coverage_report(&e)?; + } + Ok(()) } diff --git a/src/tools/miri/miri-script/src/coverage.rs b/src/tools/miri/miri-script/src/coverage.rs new file mode 100644 index 0000000000000..8cafcea0d16f3 --- /dev/null +++ b/src/tools/miri/miri-script/src/coverage.rs @@ -0,0 +1,91 @@ +use std::path::PathBuf; + +use anyhow::{Context, Result}; +use path_macro::path; +use tempfile::TempDir; +use xshell::cmd; + +use crate::util::MiriEnv; + +/// CoverageReport can generate code coverage reports for miri. +pub struct CoverageReport { + /// path is a temporary directory where intermediate coverage artifacts will be stored. + /// (The final output will be stored in a permanent location.) + path: TempDir, +} + +impl CoverageReport { + /// Creates a new CoverageReport. + /// + /// # Errors + /// + /// An error will be returned if a temporary directory could not be created. + pub fn new() -> Result { + Ok(Self { path: TempDir::new()? }) + } + + /// add_env_vars will add the required environment variables to MiriEnv `e`. + pub fn add_env_vars(&self, e: &mut MiriEnv) -> Result<()> { + let mut rustflags = e.sh.var("RUSTFLAGS")?; + rustflags.push_str(" -C instrument-coverage"); + e.sh.set_var("RUSTFLAGS", rustflags); + + // Copy-pasting from: https://doc.rust-lang.org/rustc/instrument-coverage.html#instrumentation-based-code-coverage + // The format symbols below have the following meaning: + // - %p - The process ID. + // - %Nm - the instrumented binary’s signature: + // The runtime creates a pool of N raw profiles, used for on-line + // profile merging. The runtime takes care of selecting a raw profile + // from the pool, locking it, and updating it before the program + // exits. N must be between 1 and 9, and defaults to 1 if omitted + // (with simply %m). + // + // Additionally the default for LLVM_PROFILE_FILE is default_%m_%p.profraw. + // So we just use the same template, replacing "default" with "miri". + let file_template = self.path.path().join("miri_%m_%p.profraw"); + e.sh.set_var("LLVM_PROFILE_FILE", file_template); + Ok(()) + } + + /// show_coverage_report will print coverage information using the artifact + /// files in `self.path`. + pub fn show_coverage_report(&self, e: &MiriEnv) -> Result<()> { + let profraw_files = self.profraw_files()?; + + let profdata_bin = path!(e.libdir / ".." / "bin" / "llvm-profdata"); + + let merged_file = path!(e.miri_dir / "target" / "coverage.profdata"); + + // Merge the profraw files + cmd!(e.sh, "{profdata_bin} merge -sparse {profraw_files...} -o {merged_file}") + .quiet() + .run()?; + + // Create the coverage report. + let cov_bin = path!(e.libdir / ".." / "bin" / "llvm-cov"); + let miri_bin = + e.build_get_binary(".").context("failed to get filename of miri executable")?; + cmd!( + e.sh, + "{cov_bin} report --instr-profile={merged_file} --object {miri_bin} --sources src/" + ) + .run()?; + + println!("Profile data saved in {}", merged_file.display()); + Ok(()) + } + + /// profraw_files returns the profraw files in `self.path`. + /// + /// # Errors + /// + /// An error will be returned if `self.path` can't be read. + fn profraw_files(&self) -> Result> { + Ok(std::fs::read_dir(&self.path)? + .filter_map(|r| r.ok()) + .filter(|e| e.file_type().is_ok_and(|t| t.is_file())) + .map(|e| e.path()) + .filter(|p| p.extension().is_some_and(|e| e == "profraw")) + .collect()) + } +} diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 0620f3aaf0993..a329f62790338 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -2,6 +2,7 @@ mod args; mod commands; +mod coverage; mod util; use std::ops::Range; @@ -34,6 +35,8 @@ pub enum Command { /// The cross-interpretation target. /// If none then the host is the target. target: Option, + /// Produce coverage report if set. + coverage: bool, /// Flags that are passed through to the test harness. flags: Vec, }, @@ -158,9 +161,12 @@ fn main() -> Result<()> { let mut target = None; let mut bless = false; let mut flags = Vec::new(); + let mut coverage = false; loop { if args.get_long_flag("bless")? { bless = true; + } else if args.get_long_flag("coverage")? { + coverage = true; } else if let Some(val) = args.get_long_opt("target")? { target = Some(val); } else if let Some(flag) = args.get_other() { @@ -169,7 +175,7 @@ fn main() -> Result<()> { break; } } - Command::Test { bless, flags, target } + Command::Test { bless, flags, target, coverage } } Some("run") => { let mut dep = false; diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index f5a6a8188a0dc..e6e85747d4d5f 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -41,6 +41,8 @@ pub struct MiriEnv { pub sysroot: PathBuf, /// The shell we use. pub sh: Shell, + /// The library dir in the sysroot. + pub libdir: PathBuf, } impl MiriEnv { @@ -96,7 +98,8 @@ impl MiriEnv { // so that Windows can find the DLLs. if cfg!(windows) { let old_path = sh.var("PATH")?; - let new_path = env::join_paths(iter::once(libdir).chain(env::split_paths(&old_path)))?; + let new_path = + env::join_paths(iter::once(libdir.clone()).chain(env::split_paths(&old_path)))?; sh.set_var("PATH", new_path); } @@ -111,7 +114,7 @@ impl MiriEnv { std::process::exit(1); } - Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags }) + Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags, libdir }) } pub fn cargo_cmd(&self, crate_dir: impl AsRef, cmd: &str) -> Cmd<'_> { diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 133edd3191d5b..bec28af6257fa 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -814df6e50eaf89b90793e7d9618bb60f1f18377a +668959740f97e7a22ae340742886d330ab63950f diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index b9d82a086203d..fe7d8db245b94 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -111,8 +111,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Returns the exposed `AllocId` that corresponds to the specified addr, // or `None` if the addr is out of bounds fn alloc_id_from_addr(&self, addr: u64, size: i64) -> Option { - let ecx = self.eval_context_ref(); - let global_state = ecx.machine.alloc_addresses.borrow(); + let this = self.eval_context_ref(); + let global_state = this.machine.alloc_addresses.borrow(); assert!(global_state.provenance_mode != ProvenanceMode::Strict); // We always search the allocation to the right of this address. So if the size is structly @@ -134,7 +134,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // entered for addresses that are not the base address, so even zero-sized // allocations will get recognized at their base address -- but all other // allocations will *not* be recognized at their "end" address. - let size = ecx.get_alloc_info(alloc_id).size; + let size = this.get_alloc_info(alloc_id).size; if offset < size.bytes() { Some(alloc_id) } else { None } } }?; @@ -142,7 +142,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // We only use this provenance if it has been exposed. if global_state.exposed.contains(&alloc_id) { // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. - debug_assert!(ecx.is_alloc_live(alloc_id)); + debug_assert!(this.is_alloc_live(alloc_id)); Some(alloc_id) } else { None @@ -155,9 +155,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_id: AllocId, memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { - let ecx = self.eval_context_ref(); - let mut rng = ecx.machine.rng.borrow_mut(); - let info = ecx.get_alloc_info(alloc_id); + let this = self.eval_context_ref(); + let mut rng = this.machine.rng.borrow_mut(); + let info = this.get_alloc_info(alloc_id); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an @@ -166,12 +166,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { assert!(!matches!(info.kind, AllocKind::Dead)); // This allocation does not have a base address yet, pick or reuse one. - if ecx.machine.native_lib.is_some() { + if this.machine.native_lib.is_some() { // In native lib mode, we use the "real" address of the bytes for this allocation. // This ensures the interpreted program and native code have the same view of memory. let base_ptr = match info.kind { AllocKind::LiveData => { - if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { + if this.tcx.try_get_global_alloc(alloc_id).is_some() { // For new global allocations, we always pre-allocate the memory to be able use the machine address directly. let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align) .unwrap_or_else(|| { @@ -185,7 +185,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .unwrap(); ptr } else { - ecx.get_alloc_bytes_unchecked_raw(alloc_id)? + this.get_alloc_bytes_unchecked_raw(alloc_id)? } } AllocKind::Function | AllocKind::VTable => { @@ -203,11 +203,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(base_ptr.expose_provenance().try_into().unwrap()); } // We are not in native lib mode, so we control the addresses ourselves. - if let Some((reuse_addr, clock)) = - global_state.reuse.take_addr(&mut *rng, info.size, info.align, memory_kind, ecx.active_thread()) - { + if let Some((reuse_addr, clock)) = global_state.reuse.take_addr( + &mut *rng, + info.size, + info.align, + memory_kind, + this.active_thread(), + ) { if let Some(clock) = clock { - ecx.acquire_clock(&clock); + this.acquire_clock(&clock); } interp_ok(reuse_addr) } else { @@ -230,7 +234,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .checked_add(max(info.size.bytes(), 1)) .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; // Even if `Size` didn't overflow, we might still have filled up the address space. - if global_state.next_base_addr > ecx.target_usize_max() { + if global_state.next_base_addr > this.target_usize_max() { throw_exhaust!(AddressSpaceFull); } @@ -243,8 +247,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_id: AllocId, memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { - let ecx = self.eval_context_ref(); - let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); + let this = self.eval_context_ref(); + let mut global_state = this.machine.alloc_addresses.borrow_mut(); let global_state = &mut *global_state; match global_state.base_addr.get(&alloc_id) { @@ -283,22 +287,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn expose_ptr(&mut self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { - let ecx = self.eval_context_mut(); - let global_state = ecx.machine.alloc_addresses.get_mut(); + let this = self.eval_context_mut(); + let global_state = this.machine.alloc_addresses.get_mut(); // In strict mode, we don't need this, so we can save some cycles by not tracking it. if global_state.provenance_mode == ProvenanceMode::Strict { return interp_ok(()); } // Exposing a dead alloc is a no-op, because it's not possible to get a dead allocation // via int2ptr. - if !ecx.is_alloc_live(alloc_id) { + if !this.is_alloc_live(alloc_id) { return interp_ok(()); } trace!("Exposing allocation id {alloc_id:?}"); - let global_state = ecx.machine.alloc_addresses.get_mut(); + let global_state = this.machine.alloc_addresses.get_mut(); global_state.exposed.insert(alloc_id); - if ecx.machine.borrow_tracker.is_some() { - ecx.expose_tag(alloc_id, tag)?; + if this.machine.borrow_tracker.is_some() { + this.expose_tag(alloc_id, tag)?; } interp_ok(()) } @@ -306,8 +310,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer> { trace!("Casting {:#x} to a pointer", addr); - let ecx = self.eval_context_ref(); - let global_state = ecx.machine.alloc_addresses.borrow(); + let this = self.eval_context_ref(); + let global_state = this.machine.alloc_addresses.borrow(); // Potentially emit a warning. match global_state.provenance_mode { @@ -319,9 +323,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } PAST_WARNINGS.with_borrow_mut(|past_warnings| { let first = past_warnings.is_empty(); - if past_warnings.insert(ecx.cur_span()) { + if past_warnings.insert(this.cur_span()) { // Newly inserted, so first time we see this span. - ecx.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); + this.emit_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); } }); } @@ -347,19 +351,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { tag: BorTag, kind: MemoryKind, ) -> InterpResult<'tcx, interpret::Pointer> { - let ecx = self.eval_context_ref(); + let this = self.eval_context_ref(); let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) let alloc_id = prov.alloc_id(); // Get a pointer to the beginning of this allocation. - let base_addr = ecx.addr_from_alloc_id(alloc_id, kind)?; + let base_addr = this.addr_from_alloc_id(alloc_id, kind)?; let base_ptr = interpret::Pointer::new( Provenance::Concrete { alloc_id, tag }, Size::from_bytes(base_addr), ); // Add offset with the right kind of pointer-overflowing arithmetic. - interp_ok(base_ptr.wrapping_offset(offset, ecx)) + interp_ok(base_ptr.wrapping_offset(offset, this)) } // This returns some prepared `MiriAllocBytes`, either because `addr_from_alloc_id` reserved @@ -371,16 +375,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { bytes: &[u8], align: Align, ) -> InterpResult<'tcx, MiriAllocBytes> { - let ecx = self.eval_context_ref(); - if ecx.machine.native_lib.is_some() { + let this = self.eval_context_ref(); + if this.machine.native_lib.is_some() { // In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`. // This additional call ensures that some `MiriAllocBytes` are always prepared, just in case // this function gets called before the first time `addr_from_alloc_id` gets called. - ecx.addr_from_alloc_id(id, kind)?; + this.addr_from_alloc_id(id, kind)?; // The memory we need here will have already been allocated during an earlier call to // `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead // fetch the previously prepared bytes from `prepared_alloc_bytes`. - let mut global_state = ecx.machine.alloc_addresses.borrow_mut(); + let mut global_state = this.machine.alloc_addresses.borrow_mut(); let mut prepared_alloc_bytes = global_state .prepared_alloc_bytes .remove(&id) @@ -403,7 +407,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ptr: interpret::Pointer, size: i64, ) -> Option<(AllocId, Size)> { - let ecx = self.eval_context_ref(); + let this = self.eval_context_ref(); let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) @@ -411,15 +415,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { alloc_id } else { // A wildcard pointer. - ecx.alloc_id_from_addr(addr.bytes(), size)? + this.alloc_id_from_addr(addr.bytes(), size)? }; // This cannot fail: since we already have a pointer with that provenance, adjust_alloc_root_pointer // must have been called in the past, so we can just look up the address in the map. - let base_addr = *ecx.machine.alloc_addresses.borrow().base_addr.get(&alloc_id).unwrap(); + let base_addr = *this.machine.alloc_addresses.borrow().base_addr.get(&alloc_id).unwrap(); // Wrapping "addr - base_addr" - let rel_offset = ecx.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr)); + let rel_offset = this.truncate_to_target_usize(addr.bytes().wrapping_sub(base_addr)); Some((alloc_id, Size::from_bytes(rel_offset))) } } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index f024796c0a722..dc3370f125104 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -354,7 +354,7 @@ impl<'tcx> Stack { self.borrows.get(idx).cloned() } - #[allow(clippy::len_without_is_empty)] // Stacks are never empty + #[expect(clippy::len_without_is_empty)] // Stacks are never empty pub fn len(&self) -> usize { self.borrows.len() } diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index fcd5d4641144a..02e8261a6ed90 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -1,6 +1,8 @@ +use std::cell::RefCell; use std::collections::VecDeque; use std::collections::hash_map::Entry; use std::ops::Not; +use std::rc::Rc; use std::time::Duration; use rustc_abi::Size; @@ -121,6 +123,15 @@ struct Futex { clock: VClock, } +#[derive(Default, Clone)] +pub struct FutexRef(Rc>); + +impl VisitProvenance for FutexRef { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // No provenance in `Futex`. + } +} + /// A thread waiting on a futex. #[derive(Debug)] struct FutexWaiter { @@ -137,9 +148,6 @@ pub struct SynchronizationObjects { rwlocks: IndexVec, condvars: IndexVec, pub(super) init_onces: IndexVec, - - /// Futex info for the futex at the given address. - futexes: FxHashMap, } // Private extension trait for local helper methods @@ -184,7 +192,7 @@ impl SynchronizationObjects { } impl<'tcx> AllocExtra<'tcx> { - pub fn get_sync(&self, offset: Size) -> Option<&T> { + fn get_sync(&self, offset: Size) -> Option<&T> { self.sync.get(&offset).and_then(|s| s.downcast_ref::()) } } @@ -273,27 +281,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Get the synchronization primitive associated with the given pointer, /// or initialize a new one. + /// + /// Return `None` if this pointer does not point to at least 1 byte of mutable memory. fn get_sync_or_init<'a, T: 'static>( &'a mut self, ptr: Pointer, - new: impl FnOnce(&'a mut MiriMachine<'tcx>) -> InterpResult<'tcx, T>, - ) -> InterpResult<'tcx, &'a T> + new: impl FnOnce(&'a mut MiriMachine<'tcx>) -> T, + ) -> Option<&'a T> where 'tcx: 'a, { let this = self.eval_context_mut(); - // Ensure there is memory behind this pointer, so that this allocation - // is truly the only place where the data could be stored. - this.check_ptr_access(ptr, Size::from_bytes(1), CheckInAllocMsg::InboundsTest)?; - - let (alloc, offset, _) = this.ptr_get_alloc_id(ptr, 0)?; - let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc)?; + if !this.ptr_try_get_alloc_id(ptr, 0).ok().is_some_and(|(alloc_id, offset, ..)| { + let info = this.get_alloc_info(alloc_id); + info.kind == AllocKind::LiveData && info.mutbl.is_mut() && offset < info.size + }) { + return None; + } + // This cannot fail now. + let (alloc, offset, _) = this.ptr_get_alloc_id(ptr, 0).unwrap(); + let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc).unwrap(); // Due to borrow checker reasons, we have to do the lookup twice. if alloc_extra.get_sync::(offset).is_none() { - let new = new(machine)?; + let new = new(machine); alloc_extra.sync.insert(offset, Box::new(new)); } - interp_ok(alloc_extra.get_sync::(offset).unwrap()) + Some(alloc_extra.get_sync::(offset).unwrap()) } #[inline] @@ -690,33 +703,35 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// On a timeout, `retval_timeout` is written to `dest` and `errno_timeout` is set as the last error. fn futex_wait( &mut self, - addr: u64, + futex_ref: FutexRef, bitset: u32, timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, retval_succ: Scalar, retval_timeout: Scalar, dest: MPlaceTy<'tcx>, - errno_timeout: Scalar, + errno_timeout: IoError, ) { let this = self.eval_context_mut(); let thread = this.active_thread(); - let futex = &mut this.machine.sync.futexes.entry(addr).or_default(); + let mut futex = futex_ref.0.borrow_mut(); let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread, bitset }); + drop(futex); + this.block_thread( - BlockReason::Futex { addr }, + BlockReason::Futex, timeout, callback!( @capture<'tcx> { - addr: u64, + futex_ref: FutexRef, retval_succ: Scalar, retval_timeout: Scalar, dest: MPlaceTy<'tcx>, - errno_timeout: Scalar, + errno_timeout: IoError, } @unblock = |this| { - let futex = this.machine.sync.futexes.get(&addr).unwrap(); + let futex = futex_ref.0.borrow(); // Acquire the clock of the futex. if let Some(data_race) = &this.machine.data_race { data_race.acquire_clock(&futex.clock, &this.machine.threads); @@ -728,7 +743,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @timeout = |this| { // Remove the waiter from the futex. let thread = this.active_thread(); - let futex = this.machine.sync.futexes.get_mut(&addr).unwrap(); + let mut futex = futex_ref.0.borrow_mut(); futex.waiters.retain(|waiter| waiter.thread != thread); // Set errno and write return value. this.set_last_error(errno_timeout)?; @@ -739,12 +754,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } + /// Wake up the first thread in the queue that matches any of the bits in the bitset. /// Returns whether anything was woken. - fn futex_wake(&mut self, addr: u64, bitset: u32) -> InterpResult<'tcx, bool> { + fn futex_wake(&mut self, futex_ref: &FutexRef, bitset: u32) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let Some(futex) = this.machine.sync.futexes.get_mut(&addr) else { - return interp_ok(false); - }; + let mut futex = futex_ref.0.borrow_mut(); let data_race = &this.machine.data_race; // Each futex-wake happens-before the end of the futex wait @@ -757,7 +771,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(false); }; let waiter = futex.waiters.remove(i).unwrap(); - this.unblock_thread(waiter.thread, BlockReason::Futex { addr })?; + drop(futex); + this.unblock_thread(waiter.thread, BlockReason::Futex)?; interp_ok(true) } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 281242bf373d5..e6a3ae897c23b 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -1,7 +1,6 @@ //! Implements threads. use std::mem; -use std::num::TryFromIntError; use std::sync::atomic::Ordering::Relaxed; use std::task::Poll; use std::time::{Duration, SystemTime}; @@ -127,26 +126,6 @@ impl Idx for ThreadId { } } -impl TryFrom for ThreadId { - type Error = TryFromIntError; - fn try_from(id: u64) -> Result { - u32::try_from(id).map(Self) - } -} - -impl TryFrom for ThreadId { - type Error = TryFromIntError; - fn try_from(id: i128) -> Result { - u32::try_from(id).map(Self) - } -} - -impl From for ThreadId { - fn from(id: u32) -> Self { - Self(id) - } -} - impl From for u64 { fn from(t: ThreadId) -> Self { t.0.into() @@ -168,7 +147,7 @@ pub enum BlockReason { /// Blocked on a reader-writer lock. RwLock(RwLockId), /// Blocked on a Futex variable. - Futex { addr: u64 }, + Futex, /// Blocked on an InitOnce. InitOnce(InitOnceId), /// Blocked on epoll. @@ -448,6 +427,10 @@ pub enum TimeoutAnchor { Absolute, } +/// An error signaling that the requested thread doesn't exist. +#[derive(Debug, Copy, Clone)] +pub struct ThreadNotFound; + /// A set of threads. #[derive(Debug)] pub struct ThreadManager<'tcx> { @@ -509,6 +492,16 @@ impl<'tcx> ThreadManager<'tcx> { } } + pub fn thread_id_try_from(&self, id: impl TryInto) -> Result { + if let Ok(id) = id.try_into() + && usize::try_from(id).is_ok_and(|id| id < self.threads.len()) + { + Ok(ThreadId(id)) + } else { + Err(ThreadNotFound) + } + } + /// Check if we have an allocation for the given thread local static for the /// active thread. fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { @@ -534,6 +527,7 @@ impl<'tcx> ThreadManager<'tcx> { ) -> &mut Vec>> { &mut self.threads[self.active_thread].stack } + pub fn all_stacks( &self, ) -> impl Iterator>])> { @@ -868,6 +862,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // Public interface to thread management. impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + #[inline] + fn thread_id_try_from(&self, id: impl TryInto) -> Result { + self.eval_context_ref().machine.threads.thread_id_try_from(id) + } + /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. fn get_or_create_thread_local_alloc( @@ -1160,8 +1159,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Set the name of the current thread. The buffer must not include the null terminator. #[inline] fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { - let this = self.eval_context_mut(); - this.machine.threads.set_thread_name(thread, new_thread_name); + self.eval_context_mut().machine.threads.set_thread_name(thread, new_thread_name); } #[inline] diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 800c301a82175..c610f1999f7d7 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -300,7 +300,6 @@ impl<'tcx> StoreBuffer { interp_ok(()) } - #[allow(clippy::if_same_then_else, clippy::needless_bool)] /// Selects a valid store element in the buffer. fn fetch_store( &self, diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index cbd93fbd047e3..1e56e1049187f 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -423,7 +423,7 @@ pub fn create_ecx<'tcx>( /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occurred. -#[allow(clippy::needless_lifetimes)] +#[expect(clippy::needless_lifetimes)] pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 74439d36e32f4..526030bef2e39 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -156,7 +156,7 @@ pub fn iter_exported_symbols<'tcx>( for cnum in dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| { // We add 1 to the number because that's what rustc also does everywhere it // calls `CrateNum::new`... - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) }) { // We can ignore `_export_info` here: we are a Rust crate, and everything is exported diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 895beec507b4e..272dca1594ed9 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -292,7 +292,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; let fuse: bool = this.machine.rng.get_mut().gen(); - #[allow(clippy::arithmetic_side_effects)] // float ops don't overflow let res = if fuse { // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() @@ -308,7 +307,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; let fuse: bool = this.machine.rng.get_mut().gen(); - #[allow(clippy::arithmetic_side_effects)] // float ops don't overflow let res = if fuse { // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 38a678027496a..d5c417e723142 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -750,7 +750,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if simd_element_to_bool(mask)? { // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] let ptr = ptr.wrapping_offset(dest.layout.size * i, this); let place = this.ptr_to_mplace(ptr, dest.layout); this.read_immediate(&place)? @@ -774,7 +773,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if simd_element_to_bool(mask)? { // Size * u64 is implemented as always checked - #[allow(clippy::arithmetic_side_effects)] let ptr = ptr.wrapping_offset(val.layout.size * i, this); let place = this.ptr_to_mplace(ptr, val.layout); this.write_immediate(*val, &place)? @@ -831,7 +829,7 @@ fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 { assert!(idx < vec_len); match endianness { Endian::Little => idx, - #[allow(clippy::arithmetic_side_effects)] // idx < vec_len + #[expect(clippy::arithmetic_side_effects)] // idx < vec_len Endian::Big => vec_len - 1 - idx, // reverse order of bits } } diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index c5a35bc14f591..6042a9eb2eb52 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -89,6 +89,18 @@ impl VisitProvenance for Scalar { } } +impl VisitProvenance for IoError { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + use crate::shims::io_error::IoError::*; + match self { + LibcError(_name) => (), + WindowsError(_name) => (), + HostError(_io_error) => (), + Raw(scalar) => scalar.visit_provenance(visit), + } + } +} + impl VisitProvenance for Immediate { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index b903433692437..b74491a2f8e62 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -21,7 +21,7 @@ use crate::*; #[derive(Debug, Copy, Clone)] pub struct DynSym(Symbol); -#[allow(clippy::should_implement_trait)] +#[expect(clippy::should_implement_trait)] impl DynSym { pub fn from_str(name: &str) -> Self { DynSym(Symbol::intern(name)) @@ -648,7 +648,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; // C requires that this must always be a valid pointer (C18 §7.1.4). @@ -661,7 +661,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .position(|&c| c == val) { let idx = u64::try_from(idx).unwrap(); - #[allow(clippy::arithmetic_side_effects)] // idx < num, so this never wraps + #[expect(clippy::arithmetic_side_effects)] // idx < num, so this never wraps let new_ptr = ptr.wrapping_offset(Size::from_bytes(num - idx - 1), this); this.write_pointer(new_ptr, dest)?; } else { @@ -675,7 +675,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = this.read_scalar(val)?.to_i32()?; let num = this.read_target_usize(num)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; // C requires that this must always be a valid pointer (C18 §7.1.4). diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs index 04491f0542bd8..0cbb4850b7fd9 100644 --- a/src/tools/miri/src/shims/io_error.rs +++ b/src/tools/miri/src/shims/io_error.rs @@ -7,6 +7,7 @@ use crate::*; #[derive(Debug)] pub enum IoError { LibcError(&'static str), + WindowsError(&'static str), HostError(io::Error), Raw(Scalar), } @@ -113,6 +114,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let errno = match err.into() { HostError(err) => this.io_error_to_errnum(err)?, LibcError(name) => this.eval_libc(name), + WindowsError(name) => this.eval_windows("c", name), Raw(val) => val, }; let errno_place = this.last_error_place()?; @@ -186,7 +188,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// The inverse of `io_error_to_errnum`. - #[allow(clippy::needless_return)] + #[expect(clippy::needless_return)] fn try_errnum_to_io_error( &self, errnum: Scalar, diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 6e147c58571df..46a417689a246 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -53,7 +53,7 @@ impl<'tcx> Default for TlsData<'tcx> { impl<'tcx> TlsData<'tcx> { /// Generate a new TLS key with the given destructor. /// `max_size` determines the integer size the key has to fit in. - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] pub fn create_tls_key( &mut self, dtor: Option>, diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 27465c4e8bd8e..80ad40e1624f7 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -2,6 +2,7 @@ use rustc_abi::ExternAbi; use rustc_span::Symbol; use crate::shims::unix::android::thread::prctl; +use crate::shims::unix::linux::syscall::syscall; use crate::*; pub fn is_dyn_sym(_name: &str) -> bool { @@ -26,6 +27,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } + // Dynamically invoked syscalls + "syscall" => syscall(this, link_name, abi, args, dest)?, + // Threading "prctl" => prctl(this, link_name, abi, args, dest)?, diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index 1da13d48252b0..093b7405ccda6 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -2,7 +2,7 @@ use rustc_abi::{ExternAbi, Size}; use rustc_span::Symbol; use crate::helpers::check_min_arg_count; -use crate::shims::unix::thread::EvalContextExt as _; +use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult}; use crate::*; const TASK_COMM_LEN: usize = 16; @@ -32,7 +32,7 @@ pub fn prctl<'tcx>( // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html let res = this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?; - assert!(res); + assert_eq!(res, ThreadNameResult::Ok); Scalar::from_u32(0) } op if op == pr_get_name => { @@ -46,7 +46,7 @@ pub fn prctl<'tcx>( CheckInAllocMsg::MemoryAccessTest, )?; let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?; - assert!(res); + assert_eq!(res, ThreadNameResult::Ok); Scalar::from_u32(0) } op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op), diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index d59d6712c4ff2..55202a0814922 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -603,13 +603,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_join" => { let [thread, retval] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - this.pthread_join(thread, retval)?; - this.write_null(dest)?; + let res = this.pthread_join(thread, retval)?; + this.write_scalar(res, dest)?; } "pthread_detach" => { let [thread] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - this.pthread_detach(thread)?; - this.write_null(dest)?; + let res = this.pthread_detach(thread)?; + this.write_scalar(res, dest)?; } "pthread_self" => { let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 7eaf33ace0f97..091def7ac65a0 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -385,7 +385,7 @@ pub struct DirTable { } impl DirTable { - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index c7860ac99c3e5..85f0d6e13307f 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -4,8 +4,7 @@ use rustc_span::Symbol; use self::shims::unix::linux::epoll::EvalContextExt as _; use self::shims::unix::linux::eventfd::EvalContextExt as _; use self::shims::unix::linux::mem::EvalContextExt as _; -use self::shims::unix::linux::sync::futex; -use crate::helpers::check_min_arg_count; +use self::shims::unix::linux::syscall::syscall; use crate::machine::{SIGRTMAX, SIGRTMIN}; use crate::shims::unix::*; use crate::*; @@ -82,13 +81,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pthread_setname_np" => { let [thread, name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let res = this.pthread_setname_np( + let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, TASK_COMM_LEN, /* truncate */ false, - )?; - let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"), + // Act like we faild to open `/proc/self/task/$tid/comm`. + ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"), + }; this.write_scalar(res, dest)?; } "pthread_getname_np" => { @@ -98,14 +101,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. let len = this.read_scalar(len)?; - let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 - && this.pthread_getname_np( + let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 { + match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, len, /* truncate*/ false, )? { - Scalar::from_u32(0) + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => unreachable!(), + // Act like we faild to open `/proc/self/task/$tid/comm`. + ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"), + } } else { this.eval_libc("ERANGE") }; @@ -119,57 +126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Dynamically invoked syscalls "syscall" => { - // We do not use `check_shim` here because `syscall` is variadic. The argument - // count is checked bellow. - this.check_abi_and_shim_symbol_clash( - abi, - ExternAbi::C { unwind: false }, - link_name, - )?; - // The syscall variadic function is legal to call with more arguments than needed, - // extra arguments are simply ignored. The important check is that when we use an - // argument, we have to also check all arguments *before* it to ensure that they - // have the right type. - - let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?; - let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?; - let sys_eventfd2 = this.eval_libc("SYS_eventfd2").to_target_usize(this)?; - - let [op] = check_min_arg_count("syscall", args)?; - match this.read_target_usize(op)? { - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). - num if num == sys_getrandom => { - // Used by getrandom 0.1 - // The first argument is the syscall id, so skip over it. - let [_, ptr, len, flags] = - check_min_arg_count("syscall(SYS_getrandom, ...)", args)?; - - let ptr = this.read_pointer(ptr)?; - let len = this.read_target_usize(len)?; - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG. - // See for a discussion of argument sizes. - let _flags = this.read_scalar(flags)?.to_i32()?; - - this.gen_random(ptr, len)?; - this.write_scalar(Scalar::from_target_usize(len, this), dest)?; - } - // `futex` is used by some synchronization primitives. - num if num == sys_futex => { - futex(this, args, dest)?; - } - num if num == sys_eventfd2 => { - let [_, initval, flags] = - check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?; - - let result = this.eventfd(initval, flags)?; - this.write_int(result.to_i32()?, dest)?; - } - num => { - throw_unsup_format!("syscall: unsupported syscall number {num}"); - } - } + syscall(this, link_name, abi, args, dest)?; } // Miscellaneous diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index 7597df273263a..8e796d5dce557 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let flags = this.read_scalar(flags)?.to_i32()?; // old_address must be a multiple of the page size - #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero + #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 { this.set_last_error(LibcError("EINVAL"))?; return interp_ok(this.eval_libc("MAP_FAILED")); diff --git a/src/tools/miri/src/shims/unix/linux/mod.rs b/src/tools/miri/src/shims/unix/linux/mod.rs index 84b604eb9b82e..159e5aca03105 100644 --- a/src/tools/miri/src/shims/unix/linux/mod.rs +++ b/src/tools/miri/src/shims/unix/linux/mod.rs @@ -3,3 +3,4 @@ pub mod eventfd; pub mod foreign_items; pub mod mem; pub mod sync; +pub mod syscall; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index c258be78f7647..01b011d35046e 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -1,6 +1,11 @@ +use crate::concurrency::sync::FutexRef; use crate::helpers::check_min_arg_count; use crate::*; +struct LinuxFutex { + futex: FutexRef, +} + /// Implementation of the SYS_futex syscall. /// `args` is the arguments *including* the syscall number. pub fn futex<'tcx>( @@ -27,7 +32,6 @@ pub fn futex<'tcx>( // This is a vararg function so we have to bring our own type for this pointer. let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32); - let addr_usize = addr.ptr().addr().bytes(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG"); let futex_wait = this.eval_libc_i32("FUTEX_WAIT"); @@ -63,8 +67,7 @@ pub fn futex<'tcx>( }; if bitset == 0 { - this.set_last_error_and_return(LibcError("EINVAL"), dest)?; - return interp_ok(()); + return this.set_last_error_and_return(LibcError("EINVAL"), dest); } let timeout = this.deref_pointer_as(timeout, this.libc_ty_layout("timespec"))?; @@ -99,19 +102,18 @@ pub fn futex<'tcx>( // effects of this and the other thread are correctly observed, // otherwise we will deadlock. // - // There are two scenarios to consider: - // 1. If we (FUTEX_WAIT) execute first, we'll push ourselves into - // the waiters queue and go to sleep. They (addr write & FUTEX_WAKE) - // will see us in the queue and wake us up. - // 2. If they (addr write & FUTEX_WAKE) execute first, we must observe - // addr's new value. If we see an outdated value that happens to equal - // the expected val, then we'll put ourselves to sleep with no one to wake us - // up, so we end up with a deadlock. This is prevented by having a SeqCst - // fence inside FUTEX_WAKE syscall, and another SeqCst fence - // below, the atomic read on addr after the SeqCst fence is guaranteed - // not to see any value older than the addr write immediately before - // calling FUTEX_WAKE. We'll see futex_val != val and return without - // sleeping. + // There are two scenarios to consider, depending on whether WAIT or WAKE goes first: + // 1. If we (FUTEX_WAIT) execute first, we'll push ourselves into the waiters queue and + // go to sleep. They (FUTEX_WAKE) will see us in the queue and wake us up. It doesn't + // matter how the addr write is ordered. + // 2. If they (FUTEX_WAKE) execute first, that means the addr write is also before us + // (FUTEX_WAIT). It is crucial that we observe addr's new value. If we see an + // outdated value that happens to equal the expected val, then we'll put ourselves to + // sleep with no one to wake us up, so we end up with a deadlock. This is prevented + // by having a SeqCst fence inside FUTEX_WAKE syscall, and another SeqCst fence here + // in FUTEX_WAIT. The atomic read on addr after the SeqCst fence is guaranteed not to + // see any value older than the addr write immediately before calling FUTEX_WAKE. + // We'll see futex_val != val and return without sleeping. // // Note that the fences do not create any happens-before relationship. // The read sees the write immediately before the fence not because @@ -140,17 +142,28 @@ pub fn futex<'tcx>( this.atomic_fence(AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. - let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Relaxed)?.to_i32()?; + // We do an acquire read -- it only seems reasonable that if we observe a value here, we + // actually establish an ordering with that value. + let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?; if val == futex_val { // The value still matches, so we block the thread and make it wait for FUTEX_WAKE. + + // This cannot fail since we already did an atomic acquire read on that pointer. + // Acquire reads are only allowed on mutable memory. + let futex_ref = this + .get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() }) + .unwrap() + .futex + .clone(); + this.futex_wait( - addr_usize, + futex_ref, bitset, timeout, Scalar::from_target_isize(0, this), // retval_succ Scalar::from_target_isize(-1, this), // retval_timeout dest.clone(), - this.eval_libc("ETIMEDOUT"), // errno_timeout + LibcError("ETIMEDOUT"), // errno_timeout ); } else { // The futex value doesn't match the expected value, so we return failure @@ -165,6 +178,17 @@ pub fn futex<'tcx>( // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset) // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. op if op == futex_wake || op == futex_wake_bitset => { + let Some(futex_ref) = + this.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() }) + else { + // No AllocId, or no live allocation at that AllocId. + // Return an error code. (That seems nicer than silently doing something non-intuitive.) + // This means that if an address gets reused by a new allocation, + // we'll use an independent futex queue for this... that seems acceptable. + return this.set_last_error_and_return(LibcError("EFAULT"), dest); + }; + let futex_ref = futex_ref.futex.clone(); + let bitset = if op == futex_wake_bitset { let [_, _, _, _, timeout, uaddr2, bitset] = check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?; @@ -182,9 +206,9 @@ pub fn futex<'tcx>( // before doing the syscall. this.atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; - #[allow(clippy::arithmetic_side_effects)] + #[expect(clippy::arithmetic_side_effects)] for _ in 0..val { - if this.futex_wake(addr_usize, bitset)? { + if this.futex_wake(&futex_ref, bitset)? { n += 1; } else { break; diff --git a/src/tools/miri/src/shims/unix/linux/syscall.rs b/src/tools/miri/src/shims/unix/linux/syscall.rs new file mode 100644 index 0000000000000..0d7032adab43e --- /dev/null +++ b/src/tools/miri/src/shims/unix/linux/syscall.rs @@ -0,0 +1,63 @@ +use rustc_abi::ExternAbi; +use rustc_span::Symbol; + +use self::shims::unix::linux::eventfd::EvalContextExt as _; +use crate::helpers::check_min_arg_count; +use crate::shims::unix::linux::sync::futex; +use crate::*; + +pub fn syscall<'tcx>( + this: &mut MiriInterpCx<'tcx>, + link_name: Symbol, + abi: ExternAbi, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx> { + // We do not use `check_shim` here because `syscall` is variadic. The argument + // count is checked bellow. + this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?; + // The syscall variadic function is legal to call with more arguments than needed, + // extra arguments are simply ignored. The important check is that when we use an + // argument, we have to also check all arguments *before* it to ensure that they + // have the right type. + + let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?; + let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?; + let sys_eventfd2 = this.eval_libc("SYS_eventfd2").to_target_usize(this)?; + + let [op] = check_min_arg_count("syscall", args)?; + match this.read_target_usize(op)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). + num if num == sys_getrandom => { + // Used by getrandom 0.1 + // The first argument is the syscall id, so skip over it. + let [_, ptr, len, flags] = check_min_arg_count("syscall(SYS_getrandom, ...)", args)?; + + let ptr = this.read_pointer(ptr)?; + let len = this.read_target_usize(len)?; + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG. + // See for a discussion of argument sizes. + let _flags = this.read_scalar(flags)?.to_i32()?; + + this.gen_random(ptr, len)?; + this.write_scalar(Scalar::from_target_usize(len, this), dest)?; + } + // `futex` is used by some synchronization primitives. + num if num == sys_futex => { + futex(this, args, dest)?; + } + num if num == sys_eventfd2 => { + let [_, initval, flags] = check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?; + + let result = this.eventfd(initval, flags)?; + this.write_int(result.to_i32()?, dest)?; + } + num => { + throw_unsup_format!("syscall: unsupported syscall number {num}"); + } + }; + + interp_ok(()) +} diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index b77b46e325d88..003025916cd42 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -181,18 +181,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // are met, then the name is set and 0 is returned. Otherwise, if // the specified name is lomnger than MAXTHREADNAMESIZE, then // ENAMETOOLONG is returned. - // - // FIXME: the real implementation maybe returns ESRCH if the thread ID is invalid. let thread = this.pthread_self()?; - let res = if this.pthread_setname_np( + let res = match this.pthread_setname_np( thread, this.read_scalar(name)?, this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(), /* truncate */ false, )? { - Scalar::from_u32(0) - } else { - this.eval_libc("ENAMETOOLONG") + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ENAMETOOLONG"), + ThreadNameResult::ThreadNotFound => unreachable!(), }; // Contrary to the manpage, `pthread_setname_np` on macOS still // returns an integer indicating success. @@ -210,15 +208,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1160-L1175. // The key part is the strlcpy, which truncates the resulting value, // but always null terminates (except for zero sized buffers). - // - // FIXME: the real implementation returns ESRCH if the thread ID is invalid. - let res = Scalar::from_u32(0); - this.pthread_getname_np( + let res = match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, this.read_scalar(len)?, /* truncate */ true, - )?; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + // `NameTooLong` is possible when the buffer is zero sized, + ThreadNameResult::NameTooLong => Scalar::from_u32(0), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; this.write_scalar(res, dest)?; } diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 88e04240b1197..5531b944e17d1 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -132,7 +132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // addr must be a multiple of the page size, but apart from that munmap is just implemented // as a dealloc. - #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero + #[expect(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero if addr.addr().bytes() % this.machine.page_size != 0 { return this.set_last_error_and_return_i32(LibcError("EINVAL")); } diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 9bc310e8d0a5d..c8c25c636eee3 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -21,7 +21,7 @@ pub use self::fs::{DirTable, EvalContextExt as _}; pub use self::linux::epoll::EpollInterestTable; pub use self::mem::EvalContextExt as _; pub use self::sync::EvalContextExt as _; -pub use self::thread::EvalContextExt as _; +pub use self::thread::{EvalContextExt as _, ThreadNameResult}; pub use self::unnamed_socket::EvalContextExt as _; // Make up some constants. diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index efdc64f45fcfa..526b64cff695a 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -26,26 +26,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // THREAD_NAME_MAX allows a thread name of 31+1 length // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613 let max_len = 32; - let res = this.pthread_setname_np( + // See https://illumos.org/man/3C/pthread_setname_np for the error codes. + let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, max_len, /* truncate */ false, - )?; - let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; this.write_scalar(res, dest)?; } "pthread_getname_np" => { let [thread, name, len] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - // https://github.com/illumos/illumos-gate/blob/c56822be04b6c157c8b6f2281e47214c3b86f657/usr/src/lib/libc/port/threads/thr.c#L2449-L2480 - let res = this.pthread_getname_np( + // See https://illumos.org/man/3C/pthread_getname_np for the error codes. + let res = match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, this.read_scalar(len)?, /* truncate */ false, - )?; - let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") }; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; this.write_scalar(res, dest)?; } diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 677002e79d2d4..850626d89ac15 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -685,7 +685,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let id = rwlock_get_data(this, rwlock_op)?.id; - #[allow(clippy::if_same_then_else)] if this.rwlock_reader_unlock(id)? || this.rwlock_writer_unlock(id)? { interp_ok(()) } else { diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 52c135f85409a..3d990a1a04201 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -2,6 +2,13 @@ use rustc_abi::ExternAbi; use crate::*; +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ThreadNameResult { + Ok, + NameTooLong, + ThreadNotFound, +} + impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_create( @@ -30,7 +37,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) } - fn pthread_join(&mut self, thread: &OpTy<'tcx>, retval: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { + fn pthread_join( + &mut self, + thread: &OpTy<'tcx>, + retval: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !this.ptr_is_null(this.read_pointer(retval)?)? { @@ -38,22 +49,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } - let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; - this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?; + let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(this.eval_libc("ESRCH")); + }; - interp_ok(()) + this.join_thread_exclusive(thread)?; + + interp_ok(Scalar::from_u32(0)) } - fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, ()> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; - this.detach_thread( - thread_id.try_into().expect("thread ID should fit in u32"), - /*allow_terminated_joined*/ false, - )?; + let thread = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(this.eval_libc("ESRCH")); + }; + this.detach_thread(thread, /*allow_terminated_joined*/ false)?; - interp_ok(()) + interp_ok(Scalar::from_u32(0)) } fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { @@ -65,18 +80,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Set the name of the specified thread. If the name including the null terminator /// is longer or equals to `name_max_len`, then if `truncate` is set the truncated name - /// is used as the thread name, otherwise `false` is returned. + /// is used as the thread name, otherwise [`ThreadNameResult::NameTooLong`] is returned. + /// If the specified thread wasn't found, [`ThreadNameResult::ThreadNotFound`] is returned. fn pthread_setname_np( &mut self, thread: Scalar, name: Scalar, name_max_len: usize, truncate: bool, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, ThreadNameResult> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; - let thread = ThreadId::try_from(thread).unwrap(); + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(ThreadNameResult::ThreadNotFound); + }; let name = name.to_pointer(this)?; let mut name = this.read_c_str(name)?.to_owned(); @@ -85,29 +103,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if truncate { name.truncate(name_max_len.saturating_sub(1)); } else { - return interp_ok(false); + return interp_ok(ThreadNameResult::NameTooLong); } } this.set_thread_name(thread, name); - interp_ok(true) + interp_ok(ThreadNameResult::Ok) } /// Get the name of the specified thread. If the thread name doesn't fit /// the buffer, then if `truncate` is set the truncated name is written out, - /// otherwise `false` is returned. + /// otherwise [`ThreadNameResult::NameTooLong`] is returned. If the specified + /// thread wasn't found, [`ThreadNameResult::ThreadNotFound`] is returned. fn pthread_getname_np( &mut self, thread: Scalar, name_out: Scalar, len: Scalar, truncate: bool, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, ThreadNameResult> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; - let thread = ThreadId::try_from(thread).unwrap(); + let Ok(thread) = this.thread_id_try_from(thread) else { + return interp_ok(ThreadNameResult::ThreadNotFound); + }; let name_out = name_out.to_pointer(this)?; let len = len.to_target_usize(this)?; @@ -119,8 +140,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let (success, _written) = this.write_c_str(name, name_out, len)?; + let res = if success { ThreadNameResult::Ok } else { ThreadNameResult::NameTooLong }; - interp_ok(success) + interp_ok(res) } fn sched_yield(&mut self) -> InterpResult<'tcx, ()> { diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 2c7e8d2f2e7ab..504efed3cfd53 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -10,6 +10,10 @@ use crate::shims::os_str::bytes_to_os_str; use crate::shims::windows::*; use crate::*; +// The NTSTATUS STATUS_INVALID_HANDLE (0xC0000008) encoded as a HRESULT by setting the N bit. +// (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/0642cb2f-2075-4469-918c-4441e69c548a) +const STATUS_INVALID_HANDLE: u32 = 0xD0000008; + pub fn is_dyn_sym(name: &str) -> bool { // std does dynamic detection for these symbols matches!( @@ -25,7 +29,7 @@ fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { } #[cfg(unix)] -#[allow(clippy::get_first, clippy::arithmetic_side_effects)] +#[expect(clippy::get_first, clippy::arithmetic_side_effects)] fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result> { // We are on Unix, so we need to implement parts of the logic ourselves. let bytes = path.as_os_str().as_encoded_bytes(); @@ -484,14 +488,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread_id = this.CreateThread(security, stacksize, start, arg, flags, thread)?; - this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; + this.write_scalar(Handle::Thread(thread_id.to_u32()).to_scalar(this), dest)?; } "WaitForSingleObject" => { let [handle, timeout] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; let ret = this.WaitForSingleObject(handle, timeout)?; - this.write_scalar(Scalar::from_u32(ret), dest)?; + this.write_scalar(ret, dest)?; } "GetCurrentThread" => { let [] = @@ -510,15 +514,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name = this.read_wide_str(this.read_pointer(name)?)?; let thread = match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => thread, - Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), + Some(Handle::Thread(thread)) => this.thread_id_try_from(thread), + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()), _ => this.invalid_handle("SetThreadDescription")?, }; + let res = match thread { + Ok(thread) => { + // FIXME: use non-lossy conversion + this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes()); + Scalar::from_u32(0) + } + Err(_) => Scalar::from_u32(STATUS_INVALID_HANDLE), + }; - // FIXME: use non-lossy conversion - this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes()); - - this.write_null(dest)?; + this.write_scalar(res, dest)?; } "GetThreadDescription" => { let [handle, name_ptr] = @@ -528,20 +537,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name let thread = match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => thread, - Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), - _ => this.invalid_handle("SetThreadDescription")?, + Some(Handle::Thread(thread)) => this.thread_id_try_from(thread), + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()), + _ => this.invalid_handle("GetThreadDescription")?, + }; + let (name, res) = match thread { + Ok(thread) => { + // Looks like the default thread name is empty. + let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); + let name = this.alloc_os_str_as_wide_str( + bytes_to_os_str(&name)?, + MiriMemoryKind::WinLocal.into(), + )?; + (Scalar::from_maybe_pointer(name, this), Scalar::from_u32(0)) + } + Err(_) => (Scalar::null_ptr(this), Scalar::from_u32(STATUS_INVALID_HANDLE)), }; - // Looks like the default thread name is empty. - let name = this.get_thread_name(thread).unwrap_or(b"").to_owned(); - let name = this.alloc_os_str_as_wide_str( - bytes_to_os_str(&name)?, - MiriMemoryKind::WinLocal.into(), - )?; - - this.write_scalar(Scalar::from_maybe_pointer(name, this), &name_ptr)?; - this.write_null(dest)?; + this.write_scalar(name, &name_ptr)?; + this.write_scalar(res, dest)?; } // Miscellaneous @@ -630,9 +644,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [handle] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?; - this.CloseHandle(handle)?; + let ret = this.CloseHandle(handle)?; - this.write_int(1, dest)?; + this.write_scalar(ret, dest)?; } "GetModuleFileNameW" => { let [handle, filename, size] = diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 21da3d3cdb520..b40c00efeddf4 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -14,7 +14,7 @@ pub enum PseudoHandle { pub enum Handle { Null, Pseudo(PseudoHandle), - Thread(ThreadId), + Thread(u32), } impl PseudoHandle { @@ -51,7 +51,7 @@ impl Handle { match self { Self::Null => 0, Self::Pseudo(pseudo_handle) => pseudo_handle.value(), - Self::Thread(thread) => thread.to_u32(), + Self::Thread(thread) => thread, } } @@ -63,7 +63,7 @@ impl Handle { let floor_log2 = variant_count.ilog2(); // we need to add one for non powers of two to compensate for the difference - #[allow(clippy::arithmetic_side_effects)] // cannot overflow + #[expect(clippy::arithmetic_side_effects)] // cannot overflow if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 } } @@ -88,15 +88,14 @@ impl Handle { // packs the data into the lower `data_size` bits // and packs the discriminant right above the data - #[allow(clippy::arithmetic_side_effects)] // cannot overflow - return discriminant << data_size | data; + discriminant << data_size | data } fn new(discriminant: u32, data: u32) -> Option { match discriminant { Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null), Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)), - Self::THREAD_DISCRIMINANT => Some(Self::Thread(data.into())), + Self::THREAD_DISCRIMINANT => Some(Self::Thread(data)), _ => None, } } @@ -107,11 +106,10 @@ impl Handle { let data_size = u32::BITS.strict_sub(disc_size); // the lower `data_size` bits of this mask are 1 - #[allow(clippy::arithmetic_side_effects)] // cannot overflow + #[expect(clippy::arithmetic_side_effects)] // cannot overflow let data_mask = 2u32.pow(data_size) - 1; // the discriminant is stored right above the lower `data_size` bits - #[allow(clippy::arithmetic_side_effects)] // cannot overflow let discriminant = handle >> data_size; // the data is stored in the lower `data_size` bits @@ -123,7 +121,7 @@ impl Handle { pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication - #[allow(clippy::cast_possible_wrap)] // we want it to wrap + #[expect(clippy::cast_possible_wrap)] // we want it to wrap let signed_handle = self.to_packed() as i32; Scalar::from_target_isize(signed_handle.into(), cx) } @@ -134,7 +132,7 @@ impl Handle { ) -> InterpResult<'tcx, Option> { let sign_extended_handle = handle.to_target_isize(cx)?; - #[allow(clippy::cast_sign_loss)] // we want to lose the sign + #[expect(clippy::cast_sign_loss)] // we want to lose the sign let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) { signed_handle as u32 } else { @@ -156,17 +154,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ))) } - fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx> { + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let handle = this.read_scalar(handle_op)?; - - match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => - this.detach_thread(thread, /*allow_terminated_joined*/ true)?, + let ret = match Handle::from_scalar(handle, this)? { + Some(Handle::Thread(thread)) => { + if let Ok(thread) = this.thread_id_try_from(thread) { + this.detach_thread(thread, /*allow_terminated_joined*/ true)?; + this.eval_windows("c", "TRUE") + } else { + this.invalid_handle("CloseHandle")? + } + } _ => this.invalid_handle("CloseHandle")?, - } + }; - interp_ok(()) + interp_ok(ret) } } diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index fac9c7b5fc548..b03dedea146c4 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -3,6 +3,7 @@ use std::time::Duration; use rustc_abi::Size; use crate::concurrency::init_once::InitOnceStatus; +use crate::concurrency::sync::FutexRef; use crate::*; #[derive(Copy, Clone)] @@ -10,6 +11,10 @@ struct WindowsInitOnce { id: InitOnceId, } +struct WindowsFutex { + futex: FutexRef, +} + impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows sync primitives are pointer sized. @@ -168,8 +173,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let size = this.read_target_usize(size_op)?; let timeout_ms = this.read_scalar(timeout_op)?.to_u32()?; - let addr = ptr.addr().bytes(); - if size > 8 || !size.is_power_of_two() { let invalid_param = this.eval_windows("c", "ERROR_INVALID_PARAMETER"); this.set_last_error(invalid_param)?; @@ -190,19 +193,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let layout = this.machine.layouts.uint(size).unwrap(); let futex_val = - this.read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Relaxed)?; + this.read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Acquire)?; let compare_val = this.read_scalar(&this.ptr_to_mplace(compare, layout))?; if futex_val == compare_val { // If the values are the same, we have to block. + + // This cannot fail since we already did an atomic acquire read on that pointer. + let futex_ref = this + .get_sync_or_init(ptr, |_| WindowsFutex { futex: Default::default() }) + .unwrap() + .futex + .clone(); + this.futex_wait( - addr, + futex_ref, u32::MAX, // bitset timeout, Scalar::from_i32(1), // retval_succ Scalar::from_i32(0), // retval_timeout dest.clone(), - this.eval_windows("c", "ERROR_TIMEOUT"), // errno_timeout + IoError::WindowsError("ERROR_TIMEOUT"), // errno_timeout ); } @@ -219,8 +230,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the Linux futex implementation for why this fence exists. this.atomic_fence(AtomicFenceOrd::SeqCst)?; - let addr = ptr.addr().bytes(); - this.futex_wake(addr, u32::MAX)?; + let Some(futex_ref) = + this.get_sync_or_init(ptr, |_| WindowsFutex { futex: Default::default() }) + else { + // Seems like this cannot return an error, so we just wake nobody. + return interp_ok(()); + }; + let futex_ref = futex_ref.futex.clone(); + + this.futex_wake(&futex_ref, u32::MAX)?; interp_ok(()) } @@ -232,8 +250,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // See the Linux futex implementation for why this fence exists. this.atomic_fence(AtomicFenceOrd::SeqCst)?; - let addr = ptr.addr().bytes(); - while this.futex_wake(addr, u32::MAX)? {} + let Some(futex_ref) = + this.get_sync_or_init(ptr, |_| WindowsFutex { futex: Default::default() }) + else { + // Seems like this cannot return an error, so we just wake nobody. + return interp_ok(()); + }; + let futex_ref = futex_ref.futex.clone(); + + while this.futex_wake(&futex_ref, u32::MAX)? {} interp_ok(()) } diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index fd3ef1413ed48..7af15fc647ce3 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -59,14 +59,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, handle_op: &OpTy<'tcx>, timeout_op: &OpTy<'tcx>, - ) -> InterpResult<'tcx, u32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let handle = this.read_scalar(handle_op)?; let timeout = this.read_scalar(timeout_op)?.to_u32()?; let thread = match Handle::from_scalar(handle, this)? { - Some(Handle::Thread(thread)) => thread, + Some(Handle::Thread(thread)) => + match this.thread_id_try_from(thread) { + Ok(thread) => thread, + Err(_) => this.invalid_handle("WaitForSingleObject")?, + }, // Unlike on posix, the outcome of joining the current thread is not documented. // On current Windows, it just deadlocks. Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), @@ -79,6 +83,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.join_thread(thread)?; - interp_ok(0) + interp_ok(this.eval_windows("c", "WAIT_OBJECT_0")) } } diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs index 5edbcbac3f627..7b92d422cc535 100644 --- a/src/tools/miri/src/shims/x86/gfni.rs +++ b/src/tools/miri/src/shims/x86/gfni.rs @@ -136,7 +136,7 @@ fn affine_transform<'tcx>( // This is a evaluated at compile time. Trait based conversion is not available. /// See for the /// definition of `gf_inv` which was used for the creation of this table. -#[allow(clippy::cast_possible_truncation)] +#[expect(clippy::cast_possible_truncation)] static TABLE: [u8; 256] = { let mut array = [0; 256]; @@ -163,7 +163,7 @@ static TABLE: [u8; 256] = { /// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1. /// See for details. // This is a const function. Trait based conversion is not available. -#[allow(clippy::cast_possible_truncation)] +#[expect(clippy::cast_possible_truncation)] const fn gf2p8_mul(left: u8, right: u8) -> u8 { // This implementation is based on the `gf2p8mul_byte` definition found inside the Intel intrinsics guide. // See https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 9744aa3a071f7..433e9e966f2a2 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -95,11 +95,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - "pclmulqdq" => { + "pclmulqdq" | "pclmulqdq.256" | "pclmulqdq.512" => { + let mut len = 2; // in units of 64bits + this.expect_target_feature_for_intrinsic(link_name, "pclmulqdq")?; + if unprefixed_name.ends_with(".256") { + this.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; + len = 4; + } else if unprefixed_name.ends_with(".512") { + this.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; + this.expect_target_feature_for_intrinsic(link_name, "avx512f")?; + len = 8; + } + let [left, right, imm] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - pclmulqdq(this, left, right, imm, dest)?; + pclmulqdq(this, left, right, imm, dest, len)?; } name if name.starts_with("bmi.") => { @@ -386,7 +397,6 @@ enum FloatUnaryOp { } /// Performs `which` scalar operation on `op` and returns the result. -#[allow(clippy::arithmetic_side_effects)] // floating point operations without side effects fn unary_op_f32<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, @@ -415,7 +425,7 @@ fn unary_op_f32<'tcx>( } /// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale). -#[allow(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic +#[expect(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic fn apply_random_float_error( this: &mut crate::MiriInterpCx<'_>, val: F, @@ -1122,7 +1132,7 @@ fn pmulhrsw<'tcx>( // The result of this operation can overflow a signed 16-bit integer. // When `left` and `right` are -0x8000, the result is 0x8000. - #[allow(clippy::cast_possible_truncation)] + #[expect(clippy::cast_possible_truncation)] let res = res as i16; this.write_scalar(Scalar::from_i16(res), &dest)?; @@ -1134,9 +1144,12 @@ fn pmulhrsw<'tcx>( /// Perform a carry-less multiplication of two 64-bit integers, selected from `left` and `right` according to `imm8`, /// and store the results in `dst`. /// -/// `left` and `right` are both vectors of type 2 x i64. Only bits 0 and 4 of `imm8` matter; +/// `left` and `right` are both vectors of type `len` x i64. Only bits 0 and 4 of `imm8` matter; /// they select the element of `left` and `right`, respectively. /// +/// `len` is the SIMD vector length (in counts of `i64` values). It is expected to be one of +/// `2`, `4`, or `8`. +/// /// fn pclmulqdq<'tcx>( this: &mut MiriInterpCx<'tcx>, @@ -1144,51 +1157,55 @@ fn pclmulqdq<'tcx>( right: &OpTy<'tcx>, imm8: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, + len: u64, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, right.layout); assert_eq!(left.layout.size, dest.layout.size); + assert!([2u64, 4, 8].contains(&len)); - // Transmute to `[u64; 2]` + // Transmute the input into arrays of `[u64; len]`. + // Transmute the output into an array of `[u128, len / 2]`. - let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?; - let left = left.transmute(array_layout, this)?; - let right = right.transmute(array_layout, this)?; - let dest = dest.transmute(array_layout, this)?; + let src_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, len))?; + let dest_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u128, len / 2))?; + + let left = left.transmute(src_layout, this)?; + let right = right.transmute(src_layout, this)?; + let dest = dest.transmute(dest_layout, this)?; let imm8 = this.read_scalar(imm8)?.to_u8()?; - // select the 64-bit integer from left that the user specified (low or high) - let index = if (imm8 & 0x01) == 0 { 0 } else { 1 }; - let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u64()?; - - // select the 64-bit integer from right that the user specified (low or high) - let index = if (imm8 & 0x10) == 0 { 0 } else { 1 }; - let right = this.read_scalar(&this.project_index(&right, index)?)?.to_u64()?; - - // Perform carry-less multiplication - // - // This operation is like long multiplication, but ignores all carries. - // That idea corresponds to the xor operator, which is used in the implementation. - // - // Wikipedia has an example https://en.wikipedia.org/wiki/Carry-less_product#Example - let mut result: u128 = 0; - - for i in 0..64 { - // if the i-th bit in right is set - if (right & (1 << i)) != 0 { - // xor result with `left` shifted to the left by i positions - result ^= u128::from(left) << i; + for i in 0..(len / 2) { + let lo = i.strict_mul(2); + let hi = i.strict_mul(2).strict_add(1); + + // select the 64-bit integer from left that the user specified (low or high) + let index = if (imm8 & 0x01) == 0 { lo } else { hi }; + let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u64()?; + + // select the 64-bit integer from right that the user specified (low or high) + let index = if (imm8 & 0x10) == 0 { lo } else { hi }; + let right = this.read_scalar(&this.project_index(&right, index)?)?.to_u64()?; + + // Perform carry-less multiplication. + // + // This operation is like long multiplication, but ignores all carries. + // That idea corresponds to the xor operator, which is used in the implementation. + // + // Wikipedia has an example https://en.wikipedia.org/wiki/Carry-less_product#Example + let mut result: u128 = 0; + + for i in 0..64 { + // if the i-th bit in right is set + if (right & (1 << i)) != 0 { + // xor result with `left` shifted to the left by i positions + result ^= u128::from(left) << i; + } } - } - - let result_low = (result & 0xFFFF_FFFF_FFFF_FFFF) as u64; - let result_high = (result >> 64) as u64; - - let dest_low = this.project_index(&dest, 0)?; - this.write_scalar(Scalar::from_u64(result_low), &dest_low)?; - let dest_high = this.project_index(&dest, 1)?; - this.write_scalar(Scalar::from_u64(result_high), &dest_high)?; + let dest = this.project_index(&dest, i)?; + this.write_scalar(Scalar::from_u128(result), &dest)?; + } interp_ok(()) } diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs index 4bd87b719b0ce..cc7cfab504195 100644 --- a/src/tools/miri/src/shims/x86/sse42.rs +++ b/src/tools/miri/src/shims/x86/sse42.rs @@ -68,7 +68,7 @@ const USE_SIGNED: u8 = 2; /// The mask may be negated if negation flags inside the immediate byte are set. /// /// For more information, see the Intel Software Developer's Manual, Vol. 2b, Chapter 4.1. -#[allow(clippy::arithmetic_side_effects)] +#[expect(clippy::arithmetic_side_effects)] fn compare_strings<'tcx>( this: &mut MiriInterpCx<'tcx>, str1: &OpTy<'tcx>, @@ -444,7 +444,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let crc = if bit_size == 64 { // The 64-bit version will only consider the lower 32 bits, // while the upper 32 bits get discarded. - #[allow(clippy::cast_possible_truncation)] + #[expect(clippy::cast_possible_truncation)] u128::from((left.to_u64()? as u32).reverse_bits()) } else { u128::from(left.to_u32()?.reverse_bits()) diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs index 20e642a0a2952..3adeb89ecec72 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs @@ -1,4 +1,4 @@ -//@only-target: linux +//@only-target: linux android //@compile-flags: -Zmiri-disable-isolation // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint @@ -7,8 +7,8 @@ use std::mem::MaybeUninit; use std::ptr::{self, addr_of}; use std::sync::atomic::{AtomicI32, Ordering}; -use std::thread; use std::time::{Duration, Instant}; +use std::{io, thread}; fn wake_nobody() { let futex = 0; @@ -40,9 +40,12 @@ fn wake_dangling() { let ptr: *const i32 = &*futex; drop(futex); - // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + // Expect error since this is now "unmapped" memory. + // parking_lot relies on this: + // unsafe { - assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1), 0); + assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1), -1); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EFAULT); } } diff --git a/src/tools/miri/tests/pass-dep/libc/libc-random.rs b/src/tools/miri/tests/pass-dep/libc/libc-random.rs index 8f4398cbd8fe1..7c4010f6c0ac6 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-random.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-random.rs @@ -28,26 +28,27 @@ fn test_getrandom() { let mut buf = [0u8; 5]; unsafe { - #[cfg(target_os = "linux")] - assert_eq!( - libc::syscall( - libc::SYS_getrandom, - ptr::null_mut::(), - 0 as libc::size_t, - 0 as libc::c_uint, - ), - 0, - ); - #[cfg(target_os = "linux")] - assert_eq!( - libc::syscall( - libc::SYS_getrandom, - buf.as_mut_ptr() as *mut libc::c_void, - 5 as libc::size_t, - 0 as libc::c_uint, - ), - 5, - ); + #[cfg(any(target_os = "linux", target_os = "android"))] + { + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + ptr::null_mut::(), + 0 as libc::size_t, + 0 as libc::c_uint, + ), + 0, + ); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint, + ), + 5, + ); + } assert_eq!( libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs index 75848bd44db70..fa11b5b129906 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs @@ -22,6 +22,22 @@ fn main() { check_condattr(); } +// We want to only use pthread APIs here for easier testing. +// So we can't use `thread::scope`. That means panics can lead +// to a failure to join threads which can lead to further issues, +// so let's turn such unwinding into aborts. +struct AbortOnDrop; +impl AbortOnDrop { + fn defuse(self) { + mem::forget(self); + } +} +impl Drop for AbortOnDrop { + fn drop(&mut self) { + std::process::abort(); + } +} + fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = mem::zeroed(); @@ -122,6 +138,7 @@ impl Clone for SendPtr { } fn check_mutex() { + let bomb = AbortOnDrop; // Specifically *not* using `Arc` to make sure there is no synchronization apart from the mutex. unsafe { let data = SyncUnsafeCell::new((libc::PTHREAD_MUTEX_INITIALIZER, 0)); @@ -148,9 +165,11 @@ fn check_mutex() { assert_eq!(libc::pthread_mutex_trylock(mutexptr), 0); assert_eq!((*ptr.ptr).1, 3); } + bomb.defuse(); } fn check_rwlock_write() { + let bomb = AbortOnDrop; unsafe { let data = SyncUnsafeCell::new((libc::PTHREAD_RWLOCK_INITIALIZER, 0)); let ptr = SendPtr { ptr: data.get() }; @@ -187,9 +206,11 @@ fn check_rwlock_write() { assert_eq!(libc::pthread_rwlock_tryrdlock(rwlockptr), 0); assert_eq!((*ptr.ptr).1, 3); } + bomb.defuse(); } fn check_rwlock_read_no_deadlock() { + let bomb = AbortOnDrop; unsafe { let l1 = SyncUnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); let l1 = SendPtr { ptr: l1.get() }; @@ -213,9 +234,11 @@ fn check_rwlock_read_no_deadlock() { assert_eq!(libc::pthread_rwlock_rdlock(l2.ptr), 0); handle.join().unwrap(); } + bomb.defuse(); } fn check_cond() { + let bomb = AbortOnDrop; unsafe { let mut cond: MaybeUninit = MaybeUninit::uninit(); assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), ptr::null()), 0); @@ -260,6 +283,7 @@ fn check_cond() { t.join().unwrap(); } + bomb.defuse(); } fn check_condattr() { diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index 0e5b501bbccdc..cf634bc689093 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -199,4 +199,29 @@ fn main() { .unwrap() .join() .unwrap(); + + // Now set the name for a non-existing thread and verify error codes. + // (FreeBSD doesn't return an error code.) + #[cfg(not(target_os = "freebsd"))] + { + let invalid_thread = 0xdeadbeef; + let error = { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + libc::ENOENT + } else { + libc::ESRCH + } + } + }; + #[cfg(not(target_os = "macos"))] + { + // macOS has no `setname` function accepting a thread id as the first argument. + let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) }; + assert_eq!(res, error); + } + let mut buf = [0; 64]; + let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) }; + assert_eq!(res, error); + } } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs index 4e892e6e3cb38..ae5731bc8a6a3 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-sha.rs @@ -181,7 +181,7 @@ unsafe fn schedule(v0: __m128i, v1: __m128i, v2: __m128i, v3: __m128i) -> __m128 } // we use unaligned loads with `__m128i` pointers -#[allow(clippy::cast_ptr_alignment)] +#[expect(clippy::cast_ptr_alignment)] #[target_feature(enable = "sha,sse2,ssse3,sse4.1")] unsafe fn digest_blocks(state: &mut [u32; 8], blocks: &[[u8; 64]]) { #[allow(non_snake_case)] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs new file mode 100644 index 0000000000000..68964728e4ea4 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs @@ -0,0 +1,193 @@ +// We're testing x86 target specific features +//@revisions: avx512 avx +//@only-target: x86_64 i686 +//@[avx512]compile-flags: -C target-feature=+vpclmulqdq,+avx512f +//@[avx]compile-flags: -C target-feature=+vpclmulqdq,+avx2 + +// The constants in the tests below are just bit patterns. They should not +// be interpreted as integers; signedness does not make sense for them, but +// __mXXXi happens to be defined in terms of signed integers. +#![allow(overflowing_literals)] +#![feature(avx512_target_feature)] +#![feature(stdarch_x86_avx512)] + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; +use std::mem::transmute; + +fn main() { + // Mostly copied from library/stdarch/crates/core_arch/src/x86/vpclmulqdq.rs + + assert!(is_x86_feature_detected!("pclmulqdq")); + assert!(is_x86_feature_detected!("vpclmulqdq")); + + unsafe { + test_mm256_clmulepi64_epi128(); + + if is_x86_feature_detected!("avx512f") { + test_mm512_clmulepi64_epi128(); + } + } +} + +macro_rules! verify_kat_pclmul { + ($broadcast:ident, $clmul:ident, $assert:ident) => { + // Constants taken from https://software.intel.com/sites/default/files/managed/72/cc/clmul-wp-rev-2.02-2014-04-20.pdf + let a = _mm_set_epi64x(0x7b5b546573745665, 0x63746f725d53475d); + let a = $broadcast(a); + let b = _mm_set_epi64x(0x4869285368617929, 0x5b477565726f6e5d); + let b = $broadcast(b); + let r00 = _mm_set_epi64x(0x1d4d84c85c3440c0, 0x929633d5d36f0451); + let r00 = $broadcast(r00); + let r01 = _mm_set_epi64x(0x1bd17c8d556ab5a1, 0x7fa540ac2a281315); + let r01 = $broadcast(r01); + let r10 = _mm_set_epi64x(0x1a2bf6db3a30862f, 0xbabf262df4b7d5c9); + let r10 = $broadcast(r10); + let r11 = _mm_set_epi64x(0x1d1e1f2c592e7c45, 0xd66ee03e410fd4ed); + let r11 = $broadcast(r11); + + $assert($clmul::<0x00>(a, b), r00); + $assert($clmul::<0x10>(a, b), r01); + $assert($clmul::<0x01>(a, b), r10); + $assert($clmul::<0x11>(a, b), r11); + + let a0 = _mm_set_epi64x(0x0000000000000000, 0x8000000000000000); + let a0 = $broadcast(a0); + let r = _mm_set_epi64x(0x4000000000000000, 0x0000000000000000); + let r = $broadcast(r); + $assert($clmul::<0x00>(a0, a0), r); + } +} + +// this function tests one of the possible 4 instances +// with different inputs across lanes for the 512-bit version +#[target_feature(enable = "vpclmulqdq,avx512f")] +unsafe fn verify_512_helper( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m512i, __m512i) -> __m512i, +) { + let a = _mm512_set_epi64( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + 0xAB05CFFA2621154C, + 0x1171B47A186174C9, + 0x8C6B6C0E7595CEC9, + 0xBE3E7D4934E961BD, + ); + let b = _mm512_set_epi64( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + 0xB1927AB22F31D0EC, + 0xA9A5DA619BE4D7AF, + 0xCA2590F56884FDC6, + 0x19BE9F660038BDB5, + ); + + let a_decomp = transmute::<_, [__m128i; 4]>(a); + let b_decomp = transmute::<_, [__m128i; 4]>(b); + + let r = vectorized(a, b); + + let e_decomp = [ + linear(a_decomp[0], b_decomp[0]), + linear(a_decomp[1], b_decomp[1]), + linear(a_decomp[2], b_decomp[2]), + linear(a_decomp[3], b_decomp[3]), + ]; + let e = transmute::<_, __m512i>(e_decomp); + + assert_eq_m512i(r, e) +} + +// this function tests one of the possible 4 instances +// with different inputs across lanes for the 256-bit version +#[target_feature(enable = "vpclmulqdq")] +unsafe fn verify_256_helper( + linear: unsafe fn(__m128i, __m128i) -> __m128i, + vectorized: unsafe fn(__m256i, __m256i) -> __m256i, +) { + let a = _mm256_set_epi64x( + 0xDCB4DB3657BF0B7D, + 0x18DB0601068EDD9F, + 0xB76B908233200DC5, + 0xE478235FA8E22D5E, + ); + let b = _mm256_set_epi64x( + 0x672F6F105A94CEA7, + 0x8298B8FFCA5F829C, + 0xA3927047B3FB61D8, + 0x978093862CDE7187, + ); + + let a_decomp = transmute::<_, [__m128i; 2]>(a); + let b_decomp = transmute::<_, [__m128i; 2]>(b); + + let r = vectorized(a, b); + + let e_decomp = [linear(a_decomp[0], b_decomp[0]), linear(a_decomp[1], b_decomp[1])]; + let e = transmute::<_, __m256i>(e_decomp); + + assert_eq_m256i(r, e) +} + +#[target_feature(enable = "vpclmulqdq,avx512f")] +unsafe fn test_mm512_clmulepi64_epi128() { + verify_kat_pclmul!(_mm512_broadcast_i32x4, _mm512_clmulepi64_epi128, assert_eq_m512i); + + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x00>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x00>(a, b), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x01>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x01>(a, b), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x10>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x10>(a, b), + ); + verify_512_helper( + |a, b| _mm_clmulepi64_si128::<0x11>(a, b), + |a, b| _mm512_clmulepi64_epi128::<0x11>(a, b), + ); +} + +#[target_feature(enable = "vpclmulqdq")] +unsafe fn test_mm256_clmulepi64_epi128() { + verify_kat_pclmul!(_mm256_broadcastsi128_si256, _mm256_clmulepi64_epi128, assert_eq_m256i); + + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x00>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x00>(a, b), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x01>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x01>(a, b), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x10>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x10>(a, b), + ); + verify_256_helper( + |a, b| _mm_clmulepi64_si128::<0x11>(a, b), + |a, b| _mm256_clmulepi64_epi128::<0x11>(a, b), + ); +} + +#[track_caller] +#[target_feature(enable = "avx512f")] +unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) { + assert_eq!(transmute::<_, [u64; 8]>(a), transmute::<_, [u64; 8]>(b)) +} + +#[track_caller] +#[target_feature(enable = "avx")] +unsafe fn assert_eq_m256i(a: __m256i, b: __m256i) { + assert_eq!(transmute::<_, [u64; 4]>(a), transmute::<_, [u64; 4]>(b)) +} diff --git a/tests/coverage-run-rustdoc/doctest.coverage b/tests/coverage-run-rustdoc/doctest.coverage index 396811c5487c1..f007eb0cadea6 100644 --- a/tests/coverage-run-rustdoc/doctest.coverage +++ b/tests/coverage-run-rustdoc/doctest.coverage @@ -45,11 +45,11 @@ $DIR/doctest.rs: LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { LL| 1|//! println!("{:?}", res); LL| 1|//! } - ^0 + ^0 LL| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { LL| 1|//! res = Ok(1); LL| 1|//! } - ^0 + ^0 LL| 1|//! res = Ok(0); LL| |//! } LL| |//! // need to be explicit because rustdoc cant infer the return type diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 06dce43c3cabc..c121fa551dcfa 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -1,5 +1,5 @@ Function name: abort::main -Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02] +Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 09, 00, 0a, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 30, 00, 31, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 30, 00, 31, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 10 @@ -20,17 +20,17 @@ Number of file 0 mappings: 13 - Code(Expression(8, Sub)) at (prev + 1, 12) to (start + 0, 25) = ((c0 + (c1 + c2)) - c3) - Code(Counter(4)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(3, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(3, Sub)) at (prev + 2, 9) to (start + 0, 10) = (((c0 + (c1 + c2)) - c3) - c4) - Code(Expression(8, Sub)) at (prev + 2, 12) to (start + 0, 25) = ((c0 + (c1 + c2)) - c3) - Code(Counter(5)) at (prev + 0, 26) to (start + 0, 49) -- Code(Expression(6, Sub)) at (prev + 0, 49) to (start + 0, 50) +- Code(Expression(6, Sub)) at (prev + 0, 48) to (start + 0, 49) = (((c0 + (c1 + c2)) - c3) - c5) - Code(Expression(8, Sub)) at (prev + 4, 12) to (start + 0, 25) = ((c0 + (c1 + c2)) - c3) - Code(Counter(1)) at (prev + 0, 26) to (start + 0, 49) -- Code(Counter(2)) at (prev + 0, 49) to (start + 0, 50) +- Code(Counter(2)) at (prev + 0, 48) to (start + 0, 49) - Code(Expression(9, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + c2) - Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2) diff --git a/tests/coverage/abort.coverage b/tests/coverage/abort.coverage index 29e3ad5eda7aa..be3dadab4878b 100644 --- a/tests/coverage/abort.coverage +++ b/tests/coverage/abort.coverage @@ -18,12 +18,12 @@ LL| 6| } LL| | // See discussion (below the `Notes` section) on coverage results for the closing brace. LL| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line. - ^4 ^6 + ^4 ^6 LL| | // For the following example, the closing brace is the last character on the line. LL| | // This shows the character after the closing brace is highlighted, even if that next LL| | // character is a newline. LL| 10| if countdown < 5 { might_abort(false); } - ^4 ^6 + ^4 ^6 LL| 10| countdown -= 1; LL| | } LL| 1| Ok(()) diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map index 018fcc2c3dbb3..b3cec3901197b 100644 --- a/tests/coverage/assert.cov-map +++ b/tests/coverage/assert.cov-map @@ -1,5 +1,5 @@ Function name: assert::main -Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 09, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 09, 00, 0a, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -21,7 +21,7 @@ Number of file 0 mappings: 9 - Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32) = (((c0 + (c1 + (c2 + c3))) - c4) - c1) - Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10) -- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(3)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map index ed61e91efc29a..d6462fded130a 100644 --- a/tests/coverage/async2.cov-map +++ b/tests/coverage/async2.cov-map @@ -8,14 +8,14 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: async2::async_func::{closure#0} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 16, 23) to (start + 3, 9) - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 @@ -47,14 +47,14 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: async2::non_async_func -Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 9) - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/async2.coverage b/tests/coverage/async2.coverage index ed9bc4c239d98..cdc171180b8d6 100644 --- a/tests/coverage/async2.coverage +++ b/tests/coverage/async2.coverage @@ -11,7 +11,7 @@ LL| 1| if b { LL| 1| println!("non_async_func println in block"); LL| 1| } - ^0 + ^0 LL| 1|} LL| | LL| 1|async fn async_func() { @@ -20,7 +20,7 @@ LL| 1| if b { LL| 1| println!("async_func println in block"); LL| 1| } - ^0 + ^0 LL| 1|} LL| | LL| 1|async fn async_func_just_println() { diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index 4a8cb664dd831..0ad78a720a797 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -25,7 +25,7 @@ Number of file 0 mappings: 8 Highest counter ID seen: c4 Function name: if::branch_not -Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 06, 00, 07, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 05, 01, 01, 00, 02] +Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 05, 00, 06, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 05, 00, 06, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 05, 00, 06, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -43,7 +43,7 @@ Number of file 0 mappings: 18 true = c2 false = (c1 - c2) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 17) -- Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c1 - c2) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 10) - Branch { true: Expression(2, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10) @@ -51,13 +51,13 @@ Number of file 0 mappings: 18 false = c3 - Code(Expression(2, Sub)) at (prev + 0, 11) to (start + 2, 6) = (c1 - c3) -- Code(Counter(3)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 11) - Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 8) to (start + 0, 11) true = c4 false = (c1 - c4) - Code(Counter(4)) at (prev + 0, 12) to (start + 2, 6) -- Code(Expression(4, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c1 - c4) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 12) - Branch { true: Expression(6, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12) @@ -65,12 +65,12 @@ Number of file 0 mappings: 18 false = c5 - Code(Expression(6, Sub)) at (prev + 0, 13) to (start + 2, 6) = (c1 - c5) -- Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(5)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c5 Function name: if::branch_not_as -Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 06, 00, 07, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 06, 00, 07, 05, 01, 01, 00, 02] +Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 05, 00, 06, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 05, 00, 06, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 @@ -87,13 +87,13 @@ Number of file 0 mappings: 14 false = c2 - Code(Expression(0, Sub)) at (prev + 0, 21) to (start + 2, 6) = (c1 - c2) -- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 21) - Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 8) to (start + 0, 21) true = c3 false = (c1 - c3) - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6) -- Code(Expression(2, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(2, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c1 - c3) - Code(Counter(1)) at (prev + 1, 8) to (start + 0, 22) - Branch { true: Expression(4, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22) @@ -101,7 +101,7 @@ Number of file 0 mappings: 14 false = c4 - Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 2, 6) = (c1 - c4) -- Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(4)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 diff --git a/tests/coverage/branch/if.coverage b/tests/coverage/branch/if.coverage index 2a9a408b16aff..3d107188ca682 100644 --- a/tests/coverage/branch/if.coverage +++ b/tests/coverage/branch/if.coverage @@ -30,7 +30,7 @@ ------------------ LL| 2| say("not not a"); LL| 2| } - ^1 + ^1 LL| 3| if !!!a { ------------------ | Branch (LL:8): [True: 1, False: 2] @@ -54,7 +54,7 @@ ------------------ LL| 2| say("not not (a as bool)"); LL| 2| } - ^1 + ^1 LL| 3| if !!!(a as bool) { ------------------ | Branch (LL:8): [True: 1, False: 2] diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index d50f9f8e7afaa..adf4aba0c23a2 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -1,5 +1,5 @@ Function name: closure::main -Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 01, 01, 05, 03, 02] +Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 05, 00, 06, 01, 01, 05, 03, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -27,13 +27,13 @@ Number of file 0 mappings: 24 - Code(Counter(0)) at (prev + 8, 9) to (start + 0, 68) - Code(Counter(0)) at (prev + 10, 8) to (start + 0, 16) - Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) Highest counter ID seen: c1 Function name: closure::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -41,7 +41,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: c1 @@ -83,17 +83,16 @@ Number of file 0 mappings: 1 Highest counter ID seen: (none) Function name: closure::main::{closure#14} -Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e] +Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 +Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 179, 13) to (start + 2, 27) - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#15} @@ -113,17 +112,16 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure::main::{closure#16} -Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e] +Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 +Number of file 0 mappings: 3 - Code(Counter(0)) at (prev + 197, 13) to (start + 2, 27) - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#17} @@ -143,19 +141,19 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure::main::{closure#18} (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 12, 00, 13, 00, 01, 11, 01, 0e] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 25, 13) to (start + 2, 28) - Code(Zero) at (prev + 2, 29) to (start + 2, 18) -- Code(Zero) at (prev + 2, 18) to (start + 0, 19) +- Code(Zero) at (prev + 2, 17) to (start + 0, 18) - Code(Zero) at (prev + 1, 17) to (start + 1, 14) Highest counter ID seen: (none) Function name: closure::main::{closure#19} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 01, 01, 11, 01, 0e] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -163,13 +161,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 67, 13) to (start + 2, 28) - Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) -- Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#1} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -177,13 +175,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 82, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#2} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -191,20 +189,20 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 104, 5) to (start + 2, 20) - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#3} (unused) -Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 129, 5) to (start + 1, 20) - Code(Zero) at (prev + 1, 21) to (start + 2, 10) -- Code(Zero) at (prev + 2, 10) to (start + 0, 11) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Zero) at (prev + 1, 9) to (start + 1, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 2f040b39f88a1..3eac52eb72363 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -183,7 +183,7 @@ LL| 0| println!( LL| 0| "not called: {}", LL| 0| if is_true { "check" } else { "me" } - LL| 0| ) + LL| | ) LL| | ; LL| | LL| 1| let short_used_not_covered_closure_line_break_block_embedded_branch = @@ -202,7 +202,7 @@ LL| 1| "not called: {}", LL| 1| if is_true { "check" } else { "me" } ^0 - LL| 1| ) + LL| | ) LL| | ; LL| | LL| 1| let short_used_covered_closure_line_break_block_embedded_branch = diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map index 96e1e339e569e..40a8bdf9c1d61 100644 --- a/tests/coverage/closure_bug.cov-map +++ b/tests/coverage/closure_bug.cov-map @@ -1,5 +1,5 @@ Function name: closure_bug::main -Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 17, 00, 18, 01, 01, 01, 00, 02] +Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 16, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -11,22 +11,22 @@ Number of file 0 mappings: 17 - Code(Counter(0)) at (prev + 7, 1) to (start + 3, 10) - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14) - Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(0, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) - Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(1, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c2) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) - Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(2, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c3) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) - Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23) -- Code(Expression(3, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(3, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c4) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 diff --git a/tests/coverage/closure_bug.coverage b/tests/coverage/closure_bug.coverage index 3bf19f28072f5..cc64470baa77f 100644 --- a/tests/coverage/closure_bug.coverage +++ b/tests/coverage/closure_bug.coverage @@ -16,7 +16,7 @@ LL| | LL| 1| a(); LL| 1| if truthy { a(); } - ^0 + ^0 LL| | LL| 1| let b LL| | = @@ -27,7 +27,7 @@ LL| | LL| 1| b(); LL| 1| if truthy { b(); } - ^0 + ^0 LL| | LL| 1| let c LL| | = @@ -38,7 +38,7 @@ LL| | LL| 1| c(); LL| 1| if truthy { c(); } - ^0 + ^0 LL| | LL| 1| let d LL| | = @@ -49,6 +49,6 @@ LL| | LL| 1| d(); LL| 1| if truthy { d(); } - ^0 + ^0 LL| 1|} diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index a392d1b70288e..938e440401392 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,5 +1,5 @@ Function name: conditions::main -Raw bytes (799): 0x[01, 01, 94, 01, 09, 2b, 2f, 41, 33, 3d, 35, 39, 01, 09, 0d, 35, 1e, 39, 0d, 35, 33, 3d, 35, 39, 2f, 41, 33, 3d, 35, 39, ce, 04, 0d, 01, 09, 03, 49, 62, 31, 03, 49, 5e, 4d, 62, 31, 03, 49, 5a, 51, 5e, 4d, 62, 31, 03, 49, 87, 01, 55, 4d, 51, 83, 01, 59, 87, 01, 55, 4d, 51, 49, 7f, 83, 01, 59, 87, 01, 55, 4d, 51, 5d, 65, ae, 01, 2d, 5d, 65, aa, 01, 69, ae, 01, 2d, 5d, 65, a6, 01, 6d, aa, 01, 69, ae, 01, 2d, 5d, 65, f3, 02, 71, 69, 6d, ef, 02, 75, f3, 02, 71, 69, 6d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, d6, 02, 85, 01, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 8f, 04, 89, 01, 81, 01, 85, 01, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, f6, 03, 19, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, b7, 04, 1d, 15, 19, b3, 04, 21, b7, 04, 1d, 15, 19, ab, 04, bb, 04, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, bf, 04, ca, 04, c3, 04, 31, c7, 04, 2d, 25, 29, ce, 04, 0d, 01, 09, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, ce, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 2b, 01, 09, 01, 12, ca, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 02, 08, 00, 15, 49, 00, 16, 02, 06, 62, 02, 0f, 00, 1c, 5e, 01, 0c, 00, 19, 5a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 83, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 7f, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 7b, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, 5d, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, ae, 01, 04, 11, 00, 1e, aa, 01, 01, 10, 00, 1d, a6, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, ef, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, eb, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, e3, 02, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 04, 02, 09, 00, 0a, e3, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, de, 02, 02, 0f, 00, 1c, da, 02, 01, 0c, 00, 19, d6, 02, 00, 1d, 00, 2a, d2, 02, 00, 2e, 00, 3c, 8b, 04, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, 87, 04, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, ab, 04, 05, 09, 00, 0a, 83, 04, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, fe, 03, 02, 0f, 00, 1c, fa, 03, 01, 0c, 00, 19, f6, 03, 00, 1d, 00, 2a, f2, 03, 00, 2e, 00, 3c, b3, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, af, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, a7, 04, 02, 01, 00, 02] +Raw bytes (799): 0x[01, 01, 94, 01, 09, 2b, 2f, 41, 33, 3d, 35, 39, 01, 09, 0d, 35, 1e, 39, 0d, 35, 33, 3d, 35, 39, 2f, 41, 33, 3d, 35, 39, ce, 04, 0d, 01, 09, 03, 49, 62, 31, 03, 49, 5e, 4d, 62, 31, 03, 49, 5a, 51, 5e, 4d, 62, 31, 03, 49, 87, 01, 55, 4d, 51, 83, 01, 59, 87, 01, 55, 4d, 51, 49, 7f, 83, 01, 59, 87, 01, 55, 4d, 51, 5d, 65, ae, 01, 2d, 5d, 65, aa, 01, 69, ae, 01, 2d, 5d, 65, a6, 01, 6d, aa, 01, 69, ae, 01, 2d, 5d, 65, f3, 02, 71, 69, 6d, ef, 02, 75, f3, 02, 71, 69, 6d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, d6, 02, 85, 01, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 8f, 04, 89, 01, 81, 01, 85, 01, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, f6, 03, 19, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, b7, 04, 1d, 15, 19, b3, 04, 21, b7, 04, 1d, 15, 19, ab, 04, bb, 04, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, bf, 04, ca, 04, c3, 04, 31, c7, 04, 2d, 25, 29, ce, 04, 0d, 01, 09, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, ce, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 41, 02, 09, 00, 0a, 2b, 01, 09, 01, 12, ca, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 49, 00, 16, 02, 06, 62, 02, 0f, 00, 1c, 5e, 01, 0c, 00, 19, 5a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 83, 01, 00, 3d, 02, 0a, 59, 02, 09, 00, 0a, 7f, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 7b, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 5d, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, ae, 01, 04, 11, 00, 1e, aa, 01, 01, 10, 00, 1d, a6, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, ef, 02, 00, 41, 02, 0e, 75, 02, 0d, 00, 0e, eb, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 05, 00, 06, e3, 02, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 83, 04, 02, 09, 00, 0a, e3, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, de, 02, 02, 0f, 00, 1c, da, 02, 01, 0c, 00, 19, d6, 02, 00, 1d, 00, 2a, d2, 02, 00, 2e, 00, 3c, 8b, 04, 00, 3d, 02, 0a, 8d, 01, 02, 09, 00, 0a, 87, 04, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, ab, 04, 05, 09, 00, 0a, 83, 04, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, fe, 03, 02, 0f, 00, 1c, fa, 03, 01, 0c, 00, 19, f6, 03, 00, 1d, 00, 2a, f2, 03, 00, 2e, 00, 3c, b3, 04, 00, 3d, 02, 0a, 21, 02, 09, 00, 0a, af, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, a7, 04, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 148 @@ -154,7 +154,7 @@ Number of expressions: 148 Number of file 0 mappings: 68 - Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12) - Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10) = (c2 + (((c13 + c14) + c15) + c16)) - Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29) @@ -168,7 +168,7 @@ Number of file 0 mappings: 68 = ((c3 - c13) - c14) - Code(Expression(11, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c13 + c14) + c15) -- Code(Counter(16)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(16)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 18) = (((c13 + c14) + c15) + c16) - Code(Expression(146, Sub)) at (prev + 3, 9) to (start + 0, 15) @@ -176,7 +176,7 @@ Number of file 0 mappings: 68 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12) = (c2 + (((c13 + c14) + c15) + c16)) - Code(Counter(17)) at (prev + 1, 13) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21) = (c2 + (((c13 + c14) + c15) + c16)) - Code(Counter(18)) at (prev + 0, 22) to (start + 2, 6) @@ -190,7 +190,7 @@ Number of file 0 mappings: 68 = (((((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12) - c19) - c20) - Code(Expression(32, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c19 + c20) + c21) -- Code(Counter(22)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(22)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(31, Add)) at (prev + 1, 9) to (start + 0, 23) = (((c19 + c20) + c21) + c22) - Code(Counter(12)) at (prev + 2, 9) to (start + 0, 15) @@ -198,7 +198,7 @@ Number of file 0 mappings: 68 = (c18 + (((c19 + c20) + c21) + c22)) - Code(Counter(23)) at (prev + 1, 13) to (start + 1, 16) - Code(Counter(24)) at (prev + 1, 17) to (start + 2, 10) -- Code(Zero) at (prev + 2, 10) to (start + 0, 11) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(23)) at (prev + 2, 12) to (start + 0, 25) - Code(Counter(25)) at (prev + 0, 26) to (start + 2, 10) - Code(Expression(43, Sub)) at (prev + 4, 17) to (start + 0, 30) @@ -211,15 +211,15 @@ Number of file 0 mappings: 68 = ((((c23 - c25) - c11) - c26) - c27) - Code(Expression(91, Add)) at (prev + 0, 65) to (start + 2, 14) = ((c26 + c27) + c28) -- Code(Counter(29)) at (prev + 2, 14) to (start + 0, 15) +- Code(Counter(29)) at (prev + 2, 13) to (start + 0, 14) - Code(Expression(90, Add)) at (prev + 1, 13) to (start + 0, 27) = (((c26 + c27) + c28) + c29) - Code(Counter(11)) at (prev + 2, 13) to (start + 0, 19) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(88, Add)) at (prev + 2, 9) to (start + 1, 12) = ((c25 + (((c26 + c27) + c28) + c29)) + Zero) - Code(Counter(30)) at (prev + 1, 13) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(128, Add)) at (prev + 2, 9) to (start + 0, 10) = (c31 + (((c32 + c33) + c34) + c35)) - Code(Expression(88, Add)) at (prev + 0, 16) to (start + 0, 29) @@ -235,7 +235,7 @@ Number of file 0 mappings: 68 = ((((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10) - c32) - c33) - Code(Expression(130, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c32 + c33) + c34) -- Code(Counter(35)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(35)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(129, Add)) at (prev + 1, 9) to (start + 0, 23) = (((c32 + c33) + c34) + c35) - Code(Counter(10)) at (prev + 2, 13) to (start + 2, 15) @@ -254,7 +254,7 @@ Number of file 0 mappings: 68 = (((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5) - c6) - Code(Expression(140, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c5 + c6) + c7) -- Code(Counter(8)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(8)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(139, Add)) at (prev + 1, 9) to (start + 0, 23) = (((c5 + c6) + c7) + c8) - Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15) diff --git a/tests/coverage/conditions.coverage b/tests/coverage/conditions.coverage index 48516217592e7..83944d37c9808 100644 --- a/tests/coverage/conditions.coverage +++ b/tests/coverage/conditions.coverage @@ -5,7 +5,7 @@ LL| 1| if true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| | const B: u32 = 100; LL| 1| let x = if countdown > 7 { @@ -25,7 +25,7 @@ LL| 1| if true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| 1| if countdown > 7 { LL| 1| countdown -= 4; @@ -44,7 +44,7 @@ LL| 1| if true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| 1| if countdown > 7 { LL| 1| countdown -= 4; @@ -64,7 +64,7 @@ LL| 1| if true { LL| 1| countdown = 1; LL| 1| } - ^0 + ^0 LL| | LL| 1| let z = if countdown > 7 { ^0 diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map index b94c6e656abfb..897372fe0b5e4 100644 --- a/tests/coverage/dead_code.cov-map +++ b/tests/coverage/dead_code.cov-map @@ -1,5 +1,5 @@ Function name: dead_code::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -7,32 +7,32 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 27, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: dead_code::unused_fn (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 15, 1) to (start + 7, 15) - Code(Zero) at (prev + 7, 16) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: dead_code::unused_pub_fn_not_in_library (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 3, 1) to (start + 7, 15) - Code(Zero) at (prev + 7, 16) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/dead_code.coverage b/tests/coverage/dead_code.coverage index c4ee9f23f082f..55d196f816043 100644 --- a/tests/coverage/dead_code.coverage +++ b/tests/coverage/dead_code.coverage @@ -34,6 +34,6 @@ LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1|} diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map index 8f12afac02721..a77ba8194a447 100644 --- a/tests/coverage/if.cov-map +++ b/tests/coverage/if.cov-map @@ -1,5 +1,5 @@ Function name: if::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -7,7 +7,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 4, 1) to (start + 18, 16) - Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6) -- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/if.coverage b/tests/coverage/if.coverage index 77db24ef51bf3..0762418347c22 100644 --- a/tests/coverage/if.coverage +++ b/tests/coverage/if.coverage @@ -26,6 +26,6 @@ LL| 1| 10 LL| 1| ; LL| 1| } - ^0 + ^0 LL| 1|} diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map index a2c276b7bb77b..f47139ce5a484 100644 --- a/tests/coverage/if_not.cov-map +++ b/tests/coverage/if_not.cov-map @@ -1,5 +1,5 @@ Function name: if_not::if_not -Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 @@ -10,11 +10,11 @@ Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 5, 1) to (start + 3, 13) - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6) = (c0 - c1) -- Code(Counter(1)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(1)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 2, 6) = (c0 - c2) -- Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13) - Code(Expression(2, Sub)) at (prev + 2, 5) to (start + 2, 6) = (c0 - c3) diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map index 16e86b2cadea9..a12cce25b6435 100644 --- a/tests/coverage/inner_items.cov-map +++ b/tests/coverage/inner_items.cov-map @@ -17,7 +17,7 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: inner_items::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 06, 00, 07, 01, 02, 09, 05, 02] +Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 05, 00, 06, 01, 02, 09, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -26,11 +26,11 @@ Number of expressions: 2 Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 36, 8) to (start + 0, 15) - Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6) -- Code(Expression(1, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c2) - Code(Counter(0)) at (prev + 2, 9) to (start + 5, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/inner_items.coverage index 152f3da1a2217..8244d347b59c2 100644 --- a/tests/coverage/inner_items.coverage +++ b/tests/coverage/inner_items.coverage @@ -10,7 +10,7 @@ LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| | LL| | mod in_mod { LL| | const IN_MOD_CONST: u32 = 1000; @@ -49,7 +49,7 @@ LL| 1| if is_true { LL| 1| in_func(countdown); LL| 1| } - ^0 + ^0 LL| | LL| 1| let mut val = InStruct { LL| 1| in_struct_field: 101, // diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map index fcb9d8f1ff5cc..b0c2d736573a7 100644 --- a/tests/coverage/lazy_boolean.cov-map +++ b/tests/coverage/lazy_boolean.cov-map @@ -1,5 +1,5 @@ Function name: lazy_boolean::main -Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 09, 01, 0d, 01, 19, 01, 1d, 01, 21, 01, 25, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 11, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 15, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 19, 03, 06, 00, 07, 01, 03, 09, 00, 10, 1d, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 21, 02, 06, 00, 07, 01, 02, 08, 00, 0f, 25, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 09, 01, 0d, 01, 19, 01, 1d, 01, 21, 01, 25, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 05, 00, 06, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 11, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 15, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 19, 03, 05, 00, 06, 01, 03, 09, 00, 10, 1d, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 21, 02, 05, 00, 06, 01, 02, 08, 00, 0f, 25, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 7 @@ -13,7 +13,7 @@ Number of expressions: 7 Number of file 0 mappings: 28 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17) - Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18) @@ -32,7 +32,7 @@ Number of file 0 mappings: 28 - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 16) - Code(Expression(3, Sub)) at (prev + 2, 5) to (start + 3, 6) = (c0 - c6) -- Code(Counter(6)) at (prev + 3, 6) to (start + 0, 7) +- Code(Counter(6)) at (prev + 3, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) - Code(Counter(7)) at (prev + 1, 5) to (start + 3, 6) - Code(Expression(4, Sub)) at (prev + 5, 5) to (start + 3, 6) @@ -40,7 +40,7 @@ Number of file 0 mappings: 28 - Code(Counter(0)) at (prev + 5, 8) to (start + 0, 16) - Code(Expression(5, Sub)) at (prev + 0, 17) to (start + 2, 6) = (c0 - c8) -- Code(Counter(8)) at (prev + 2, 6) to (start + 0, 7) +- Code(Counter(8)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 2, 8) to (start + 0, 15) - Code(Counter(9)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6) diff --git a/tests/coverage/lazy_boolean.coverage b/tests/coverage/lazy_boolean.coverage index f058be8390082..828ba2a581162 100644 --- a/tests/coverage/lazy_boolean.coverage +++ b/tests/coverage/lazy_boolean.coverage @@ -13,7 +13,7 @@ LL| 1| b = 10; LL| 1| c = 100; LL| 1| } - ^0 + ^0 LL| | let LL| 1| somebool LL| | = diff --git a/tests/coverage/loop-break.cov-map b/tests/coverage/loop-break.cov-map index 63280a0bf7cbe..0b4c42a43da0c 100644 --- a/tests/coverage/loop-break.cov-map +++ b/tests/coverage/loop-break.cov-map @@ -1,5 +1,5 @@ Function name: loop_break::main -Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 03, 01, 00, 0b, 03, 02, 0c, 00, 27, 01, 01, 0d, 00, 12, 05, 01, 0a, 00, 0b, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 03, 01, 00, 0b, 03, 02, 0c, 00, 27, 01, 01, 0d, 00, 12, 05, 01, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -9,7 +9,7 @@ Number of file 0 mappings: 5 - Code(Expression(0, Add)) at (prev + 2, 12) to (start + 0, 39) = (c0 + c1) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) -- Code(Counter(1)) at (prev + 1, 10) to (start + 0, 11) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 1d263611a3abc..61a6bda676a90 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,5 +1,5 @@ Function name: ::fmt -Raw bytes (228): 0x[01, 01, 2a, 05, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, a3, 01, a7, 01, 0d, 00, 11, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 8f, 01, 19, 25, 92, 01, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 05, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 9a, 01, 03, 0d, 00, 0e, 9f, 01, 00, 12, 00, 17, 9a, 01, 01, 10, 00, 14, 96, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 46, 01, 12, 00, 13, 96, 01, 01, 11, 00, 22, 92, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 8b, 01, 01, 05, 00, 06] +Raw bytes (228): 0x[01, 01, 2a, 05, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, a3, 01, a7, 01, 0d, 00, 11, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 8f, 01, 19, 25, 92, 01, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0d, 00, 0e, 05, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 9a, 01, 03, 0d, 00, 0e, 9f, 01, 00, 12, 00, 17, 9a, 01, 01, 10, 00, 14, 96, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 46, 01, 11, 00, 12, 96, 01, 01, 11, 00, 22, 92, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 8b, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 42 @@ -50,7 +50,7 @@ Number of file 0 mappings: 20 - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) -- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 14) = (c1 - Zero) - Code(Counter(1)) at (prev + 1, 13) to (start + 0, 30) - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) @@ -65,7 +65,7 @@ Number of file 0 mappings: 20 = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(17, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(17, Sub)) at (prev + 1, 17) to (start + 0, 18) = (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero) - Code(Expression(37, Sub)) at (prev + 1, 17) to (start + 0, 34) = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) @@ -78,7 +78,7 @@ Number of file 0 mappings: 20 Highest counter ID seen: c9 Function name: ::fmt -Raw bytes (230): 0x[01, 01, 2b, 01, 00, 02, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, a7, 01, ab, 01, 00, 0d, 00, 15, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 00, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 93, 01, 25, 96, 01, 19, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0e, 00, 0f, 02, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 9e, 01, 02, 0d, 00, 0e, a3, 01, 00, 12, 00, 17, 9e, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 9a, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4a, 01, 12, 00, 13, 9a, 01, 01, 11, 00, 22, 96, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, 8f, 01, 01, 05, 00, 06] +Raw bytes (230): 0x[01, 01, 2b, 01, 00, 02, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, a7, 01, ab, 01, 00, 0d, 00, 15, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 00, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 93, 01, 25, 96, 01, 19, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0d, 00, 0e, 02, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 9e, 01, 02, 0d, 00, 0e, a3, 01, 00, 12, 00, 17, 9e, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 9a, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4a, 01, 11, 00, 12, 9a, 01, 01, 11, 00, 22, 96, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, 8f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 43 @@ -132,7 +132,7 @@ Number of file 0 mappings: 20 = (c0 - Zero) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) -- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 15) +- Code(Expression(1, Sub)) at (prev + 1, 13) to (start + 0, 14) = ((c0 - Zero) - Zero) - Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 30) = (c0 - Zero) @@ -148,7 +148,7 @@ Number of file 0 mappings: 20 = ((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(18, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(18, Sub)) at (prev + 1, 17) to (start + 0, 18) = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero) - Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 34) = ((((Zero + c3) + (Zero + c5)) - c6) - Zero) diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map index f6491ea262dc5..2beb327bc0594 100644 --- a/tests/coverage/match_or_pattern.cov-map +++ b/tests/coverage/match_or_pattern.cov-map @@ -1,5 +1,5 @@ Function name: match_or_pattern::main -Raw bytes (185): 0x[01, 01, 1c, 01, 05, 09, 0d, 23, 11, 09, 0d, 1f, 15, 23, 11, 09, 0d, 23, 11, 09, 0d, 19, 1d, 43, 21, 19, 1d, 3f, 25, 43, 21, 19, 1d, 43, 21, 19, 1d, 29, 2d, 63, 31, 29, 2d, 5f, 35, 63, 31, 29, 2d, 63, 31, 29, 2d, 39, 3d, 6f, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 01, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 23, 01, 0e, 00, 10, 1f, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 06, 00, 07, 1f, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 43, 01, 0e, 00, 10, 3f, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 32, 03, 06, 00, 07, 3f, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 63, 01, 0e, 00, 10, 5f, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 52, 03, 06, 00, 07, 5f, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 6f, 01, 0e, 00, 10, 6b, 02, 01, 00, 02] +Raw bytes (185): 0x[01, 01, 1c, 01, 05, 09, 0d, 23, 11, 09, 0d, 1f, 15, 23, 11, 09, 0d, 23, 11, 09, 0d, 19, 1d, 43, 21, 19, 1d, 3f, 25, 43, 21, 19, 1d, 43, 21, 19, 1d, 29, 2d, 63, 31, 29, 2d, 5f, 35, 63, 31, 29, 2d, 63, 31, 29, 2d, 39, 3d, 6f, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 23, 01, 0e, 00, 10, 1f, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 05, 00, 06, 1f, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 43, 01, 0e, 00, 10, 3f, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 32, 03, 05, 00, 06, 3f, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 63, 01, 0e, 00, 10, 5f, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 52, 03, 05, 00, 06, 5f, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 6f, 01, 0e, 00, 10, 6b, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 28 @@ -34,7 +34,7 @@ Number of expressions: 28 Number of file 0 mappings: 25 - Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15) - Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6) -- Code(Expression(0, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 11) to (start + 0, 17) - Code(Counter(4)) at (prev + 3, 27) to (start + 0, 29) @@ -43,7 +43,7 @@ Number of file 0 mappings: 25 - Code(Expression(7, Add)) at (prev + 2, 8) to (start + 0, 15) = ((c2 + c3) + c4) - Code(Counter(5)) at (prev + 0, 16) to (start + 3, 6) -- Code(Expression(4, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(4, Sub)) at (prev + 3, 5) to (start + 0, 6) = (((c2 + c3) + c4) - c5) - Code(Expression(7, Add)) at (prev + 1, 11) to (start + 0, 17) = ((c2 + c3) + c4) @@ -53,7 +53,7 @@ Number of file 0 mappings: 25 - Code(Expression(15, Add)) at (prev + 2, 8) to (start + 0, 15) = ((c6 + c7) + c8) - Code(Counter(9)) at (prev + 0, 16) to (start + 3, 6) -- Code(Expression(12, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(12, Sub)) at (prev + 3, 5) to (start + 0, 6) = (((c6 + c7) + c8) - c9) - Code(Expression(15, Add)) at (prev + 1, 11) to (start + 0, 17) = ((c6 + c7) + c8) @@ -63,7 +63,7 @@ Number of file 0 mappings: 25 - Code(Expression(23, Add)) at (prev + 2, 8) to (start + 0, 15) = ((c10 + c11) + c12) - Code(Counter(13)) at (prev + 0, 16) to (start + 3, 6) -- Code(Expression(20, Sub)) at (prev + 3, 6) to (start + 0, 7) +- Code(Expression(20, Sub)) at (prev + 3, 5) to (start + 0, 6) = (((c10 + c11) + c12) - c13) - Code(Expression(23, Add)) at (prev + 1, 11) to (start + 0, 17) = ((c10 + c11) + c12) diff --git a/tests/coverage/match_or_pattern.coverage b/tests/coverage/match_or_pattern.coverage index 94c7967215c1b..a65c226e56727 100644 --- a/tests/coverage/match_or_pattern.coverage +++ b/tests/coverage/match_or_pattern.coverage @@ -10,7 +10,7 @@ LL| 1| a = 2; LL| 1| b = 0; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. LL| | // This test confirms a fix for Issue #79569. @@ -21,7 +21,7 @@ LL| 1| a = 0; LL| 1| b = 0; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| 0| (0 | 1, 2 | 3) => {} LL| 1| _ => {} @@ -30,7 +30,7 @@ LL| 1| a = 2; LL| 1| b = 2; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| 0| (0 | 1, 2 | 3) => {} LL| 1| _ => {} @@ -39,7 +39,7 @@ LL| 1| a = 0; LL| 1| b = 2; LL| 1| } - ^0 + ^0 LL| 1| match (a, b) { LL| 1| (0 | 1, 2 | 3) => {} LL| 0| _ => {} diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index a3e3b1d09c4d1..e3f5b49d3636c 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,5 +1,5 @@ Function name: condition_limit::accept_7_conditions -Raw bytes (232): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 7a, 1d, 07, 06, 00, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 30, 76, 19, 06, 05, 00, 00, 12, 00, 13, 76, 00, 17, 00, 18, 30, 72, 15, 05, 04, 00, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 30, 6e, 11, 04, 03, 00, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 30, 6a, 0d, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 21, 09, 02, 00, 00, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] +Raw bytes (232): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 7a, 1d, 07, 06, 00, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 30, 76, 19, 06, 05, 00, 00, 12, 00, 13, 76, 00, 17, 00, 18, 30, 72, 15, 05, 04, 00, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 30, 6e, 11, 04, 03, 00, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 30, 6a, 0d, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 21, 09, 02, 00, 00, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 05, 00, 06, 97, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 44 @@ -83,7 +83,7 @@ Number of file 0 mappings: 18 true = c8 false = c2 - Code(Counter(8)) at (prev + 0, 40) to (start + 2, 6) -- Code(Expression(38, Add)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(38, Add)) at (prev + 2, 5) to (start + 0, 6) = ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1)) - Code(Expression(37, Add)) at (prev + 1, 1) to (start + 0, 2) = (c8 + ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1))) diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index 46960d31c01e6..c0e7d08bb0280 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -175,7 +175,7 @@ Number of file 0 mappings: 10 Highest counter ID seen: c4 Function name: if::mcdc_nested_if -Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 0a, 00, 0b, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] +Raw bytes (124): 0x[01, 01, 0d, 01, 05, 02, 09, 05, 09, 1b, 15, 05, 09, 1b, 15, 05, 09, 11, 15, 02, 09, 2b, 32, 0d, 2f, 11, 15, 02, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 32, 02, 00, 00, 00, 0d, 00, 0e, 1b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 16, 15, 01, 02, 00, 00, 0c, 00, 0d, 16, 00, 11, 00, 12, 30, 0d, 11, 02, 00, 00, 00, 11, 00, 12, 0d, 00, 13, 02, 0a, 2f, 02, 09, 00, 0a, 32, 01, 0c, 02, 06, 27, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 13 @@ -215,7 +215,7 @@ Number of file 0 mappings: 14 true = c3 false = c4 - Code(Counter(3)) at (prev + 0, 19) to (start + 2, 10) -- Code(Expression(11, Add)) at (prev + 2, 10) to (start + 0, 11) +- Code(Expression(11, Add)) at (prev + 2, 9) to (start + 0, 10) = (c4 + c5) - Code(Expression(12, Sub)) at (prev + 1, 12) to (start + 2, 6) = ((c0 - c1) - c2) diff --git a/tests/coverage/nested_loops.cov-map b/tests/coverage/nested_loops.cov-map index c145d4c58433b..21871ef320646 100644 --- a/tests/coverage/nested_loops.cov-map +++ b/tests/coverage/nested_loops.cov-map @@ -1,5 +1,5 @@ Function name: nested_loops::main -Raw bytes (115): 0x[01, 01, 17, 01, 57, 05, 09, 03, 0d, 4e, 53, 03, 0d, 15, 19, 4b, 09, 4e, 53, 03, 0d, 15, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 42, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 05, 09, 11, 0d, 0d, 01, 01, 01, 02, 1b, 03, 04, 13, 00, 20, 4e, 01, 0d, 01, 18, 4b, 02, 12, 00, 17, 46, 01, 10, 00, 16, 05, 01, 11, 00, 16, 42, 01, 0e, 03, 16, 3e, 04, 11, 01, 1b, 11, 02, 15, 00, 21, 15, 01, 18, 02, 12, 19, 03, 0e, 00, 0f, 57, 02, 09, 00, 17, 5b, 02, 01, 00, 02] +Raw bytes (115): 0x[01, 01, 17, 01, 57, 05, 09, 03, 0d, 4e, 53, 03, 0d, 15, 19, 4b, 09, 4e, 53, 03, 0d, 15, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 42, 19, 46, 05, 4b, 09, 4e, 53, 03, 0d, 15, 19, 05, 09, 11, 0d, 0d, 01, 01, 01, 02, 1b, 03, 04, 13, 00, 20, 4e, 01, 0d, 01, 18, 4b, 02, 12, 00, 17, 46, 01, 10, 00, 16, 05, 01, 11, 00, 16, 42, 01, 0e, 03, 16, 3e, 04, 11, 01, 1b, 11, 02, 15, 00, 21, 15, 01, 18, 02, 12, 19, 03, 0d, 00, 0e, 57, 02, 09, 00, 17, 5b, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 23 @@ -43,7 +43,7 @@ Number of file 0 mappings: 13 = ((((((c0 + (c1 + c2)) - c3) + (c5 + c6)) - c2) - c1) - c6) - Code(Counter(4)) at (prev + 2, 21) to (start + 0, 33) - Code(Counter(5)) at (prev + 1, 24) to (start + 2, 18) -- Code(Counter(6)) at (prev + 3, 14) to (start + 0, 15) +- Code(Counter(6)) at (prev + 3, 13) to (start + 0, 14) - Code(Expression(21, Add)) at (prev + 2, 9) to (start + 0, 23) = (c1 + c2) - Code(Expression(22, Add)) at (prev + 2, 1) to (start + 0, 2) diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map index f842ce3e896b1..f6bfb465bf9a0 100644 --- a/tests/coverage/overflow.cov-map +++ b/tests/coverage/overflow.cov-map @@ -1,5 +1,5 @@ Function name: overflow::main -Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 10, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 03, 0a, 12, 03, 13, 00, 20, 09, 00, 21, 03, 0a, 0d, 03, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 10, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 03, 0a, 12, 03, 13, 00, 20, 09, 00, 21, 03, 0a, 0d, 03, 09, 00, 0a, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -21,14 +21,14 @@ Number of file 0 mappings: 9 - Code(Expression(4, Sub)) at (prev + 3, 19) to (start + 0, 32) = (((c0 + (c1 + (c2 + c3))) - c4) - c1) - Code(Counter(2)) at (prev + 0, 33) to (start + 3, 10) -- Code(Counter(3)) at (prev + 3, 10) to (start + 0, 11) +- Code(Counter(3)) at (prev + 3, 9) to (start + 0, 10) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) Highest counter ID seen: c4 Function name: overflow::might_overflow -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 01, 01, 09, 05, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 05, 00, 06, 01, 01, 09, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -36,7 +36,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 5, 1) to (start + 1, 18) - Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 9) to (start + 5, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map index f4a7894cc1cc1..58a796ff3a2c3 100644 --- a/tests/coverage/panic_unwind.cov-map +++ b/tests/coverage/panic_unwind.cov-map @@ -1,5 +1,5 @@ Function name: panic_unwind::main -Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 0a, 00, 0b, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] +Raw bytes (65): 0x[01, 01, 08, 01, 1b, 05, 1f, 09, 0d, 03, 11, 16, 05, 03, 11, 05, 1f, 09, 0d, 09, 01, 0d, 01, 01, 1b, 03, 02, 0b, 00, 18, 16, 01, 0c, 00, 1a, 05, 00, 1b, 02, 0a, 12, 02, 13, 00, 20, 09, 00, 21, 02, 0a, 0d, 02, 09, 00, 0a, 1b, 01, 09, 00, 17, 11, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -21,7 +21,7 @@ Number of file 0 mappings: 9 - Code(Expression(4, Sub)) at (prev + 2, 19) to (start + 0, 32) = (((c0 + (c1 + (c2 + c3))) - c4) - c1) - Code(Counter(2)) at (prev + 0, 33) to (start + 2, 10) -- Code(Counter(3)) at (prev + 2, 10) to (start + 0, 11) +- Code(Counter(3)) at (prev + 2, 9) to (start + 0, 10) - Code(Expression(6, Add)) at (prev + 1, 9) to (start + 0, 23) = (c1 + (c2 + c3)) - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2) diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map index b6f1e8f6afe6a..d1e684efbbcd5 100644 --- a/tests/coverage/simple_loop.cov-map +++ b/tests/coverage/simple_loop.cov-map @@ -1,5 +1,5 @@ Function name: simple_loop::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 07, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 01, 06, 01, 00, 02] +Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 05, 00, 06, 07, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 01, 06, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 @@ -8,7 +8,7 @@ Number of expressions: 2 Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 4, 1) to (start + 9, 16) - Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6) -- Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Expression(1, Add)) at (prev + 5, 13) to (start + 2, 14) = (c0 + c2) diff --git a/tests/coverage/simple_loop.coverage b/tests/coverage/simple_loop.coverage index b6552c62ff909..237e509f42e10 100644 --- a/tests/coverage/simple_loop.coverage +++ b/tests/coverage/simple_loop.coverage @@ -17,7 +17,7 @@ LL| 1| 10 LL| 1| ; LL| 1| } - ^0 + ^0 LL| | LL| | loop LL| | { diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map index b62edf12650ca..d8bf9eae4bc61 100644 --- a/tests/coverage/simple_match.cov-map +++ b/tests/coverage/simple_match.cov-map @@ -1,5 +1,5 @@ Function name: simple_match::main -Raw bytes (72): 0x[01, 01, 09, 01, 05, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1f, 05, 09, 00, 0d, 1a, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 1a, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02] +Raw bytes (72): 0x[01, 01, 09, 01, 05, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 1f, 05, 09, 00, 0d, 1a, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 1a, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 9 @@ -15,7 +15,7 @@ Number of expressions: 9 Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Expression(7, Add)) at (prev + 5, 9) to (start + 0, 13) = (c0 + (c2 + c3)) diff --git a/tests/coverage/simple_match.coverage b/tests/coverage/simple_match.coverage index 3a4fc6743f5e0..e1d5e48a2bf1f 100644 --- a/tests/coverage/simple_match.coverage +++ b/tests/coverage/simple_match.coverage @@ -11,7 +11,7 @@ LL| 1| if is_true { LL| 1| countdown = 0; LL| 1| } - ^0 + ^0 LL| | LL| | for LL| | _ diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map index 4e7ed059c879d..69e1342229609 100644 --- a/tests/coverage/sort_groups.cov-map +++ b/tests/coverage/sort_groups.cov-map @@ -1,5 +1,5 @@ Function name: sort_groups::generic_fn::<&str> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -7,13 +7,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<()> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -21,13 +21,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -35,13 +35,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -49,13 +49,13 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 02, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -63,7 +63,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 6, 1) to (start + 4, 35) - Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 2, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/sort_groups.coverage b/tests/coverage/sort_groups.coverage index 33a4d9546ce99..6e8a4eda09f1e 100644 --- a/tests/coverage/sort_groups.coverage +++ b/tests/coverage/sort_groups.coverage @@ -27,7 +27,7 @@ | LL| 1| if cond { | LL| 1| println!("{}", std::any::type_name::()); | LL| 1| } - | ^0 + | ^0 | LL| 1|} ------------------ | sort_groups::generic_fn::<()>: diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index ac4e691ea7abf..769930110d67e 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -1,5 +1,5 @@ Function name: unicode::main -Raw bytes (61): 0x[01, 01, 06, 01, 05, 16, 0d, 01, 09, 11, 13, 16, 0d, 01, 09, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 13, 02, 06, 00, 07, 0f, 02, 05, 01, 02] +Raw bytes (61): 0x[01, 01, 06, 01, 05, 16, 0d, 01, 09, 11, 13, 16, 0d, 01, 09, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 13, 02, 05, 00, 06, 0f, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 6 @@ -18,7 +18,7 @@ Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 2, 8) to (start + 0, 37) - Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70) - Code(Counter(4)) at (prev + 0, 71) to (start + 2, 6) -- Code(Expression(4, Add)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(4, Add)) at (prev + 2, 5) to (start + 0, 6) = ((c0 - c2) + c3) - Code(Expression(3, Add)) at (prev + 2, 5) to (start + 1, 2) = (c4 + ((c0 - c2) + c3)) diff --git a/tests/coverage/unicode.coverage b/tests/coverage/unicode.coverage index 305591c706258..84c5f05a8c4e2 100644 --- a/tests/coverage/unicode.coverage +++ b/tests/coverage/unicode.coverage @@ -18,7 +18,7 @@ LL| 1| if 申し訳ございません() && 申し訳ございません() { ^0 LL| 0| println!("true"); - LL| 1| } + LL| 1| } LL| | LL| 1| サビ(); LL| 1|} diff --git a/tests/coverage/unused.cov-map b/tests/coverage/unused.cov-map index 9f1ad59ce83dd..e865ac3ee6227 100644 --- a/tests/coverage/unused.cov-map +++ b/tests/coverage/unused.cov-map @@ -50,38 +50,38 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: unused::unused_func (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 19, 1) to (start + 1, 14) - Code(Zero) at (prev + 1, 15) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func2 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 25, 1) to (start + 1, 14) - Code(Zero) at (prev + 1, 15) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func3 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 - Code(Zero) at (prev + 31, 1) to (start + 1, 14) - Code(Zero) at (prev + 1, 15) to (start + 2, 6) -- Code(Zero) at (prev + 2, 6) to (start + 0, 7) +- Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage index d001eeffd8636..d1b0dadda768e 100644 --- a/tests/coverage/uses_crate.coverage +++ b/tests/coverage/uses_crate.coverage @@ -14,7 +14,7 @@ $DIR/auxiliary/used_crate.rs: LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1| use_this_lib_crate(); LL| 1|} LL| | diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map index a6909768162bd..a482d20e3b4bc 100644 --- a/tests/coverage/uses_inline_crate.cov-map +++ b/tests/coverage/uses_inline_crate.cov-map @@ -8,7 +8,7 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: used_inline_crate::used_inline_function -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 01, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 @@ -16,7 +16,7 @@ Number of expressions: 1 Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 20, 1) to (start + 6, 15) - Code(Counter(1)) at (prev + 6, 16) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/uses_inline_crate.coverage index 832a5a6a62b44..4671c95aefa49 100644 --- a/tests/coverage/uses_inline_crate.coverage +++ b/tests/coverage/uses_inline_crate.coverage @@ -14,7 +14,7 @@ $DIR/auxiliary/used_inline_crate.rs: LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1| use_this_lib_crate(); LL| 1|} LL| | @@ -28,7 +28,7 @@ $DIR/auxiliary/used_inline_crate.rs: LL| 1| if is_true { LL| 1| countdown = 10; LL| 1| } - ^0 + ^0 LL| 1| use_this_lib_crate(); LL| 1|} LL| | diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index eeeac70b5b8e7..cbb11d50f7974 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -26,18 +26,19 @@ debug a => _9; } ++ coverage body span: $DIR/branch_match_arms.rs:14:11: 21:2 (#0) + coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) }; + coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) }; + coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) }; + coverage ExpressionId(3) => Expression { lhs: Counter(3), op: Add, rhs: Counter(2) }; + coverage ExpressionId(4) => Expression { lhs: Expression(3), op: Add, rhs: Counter(1) }; + coverage ExpressionId(5) => Expression { lhs: Expression(4), op: Add, rhs: Expression(2) }; -+ coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:14:1 - 15:21; -+ coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:16:17 - 16:33; -+ coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:17:17 - 17:33; -+ coverage Code(Counter(1)) => $DIR/branch_match_arms.rs:18:17 - 18:33; -+ coverage Code(Expression(2)) => $DIR/branch_match_arms.rs:19:17 - 19:33; -+ coverage Code(Expression(5)) => $DIR/branch_match_arms.rs:21:1 - 21:2; ++ coverage Code(Counter(0)) => 14:1 - 15:21; ++ coverage Code(Counter(3)) => 16:17 - 16:33; ++ coverage Code(Counter(2)) => 17:17 - 17:33; ++ coverage Code(Counter(1)) => 18:17 - 18:33; ++ coverage Code(Expression(2)) => 19:17 - 19:33; ++ coverage Code(Expression(5)) => 21:1 - 21:2; + bb0: { + Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff index 01b01ea5c1756..2efb1fd0a17a3 100644 --- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff @@ -4,7 +4,8 @@ fn bar() -> bool { let mut _0: bool; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:19:1 - 21:2; ++ coverage body span: $DIR/instrument_coverage.rs:19:18: 21:2 (#0) ++ coverage Code(Counter(0)) => 19:1 - 21:2; + bb0: { + Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff index a594c44c316af..a179824d6c736 100644 --- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff @@ -7,12 +7,13 @@ let mut _2: bool; let mut _3: !; ++ coverage body span: $DIR/instrument_coverage.rs:10:11: 16:2 (#0) + coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) }; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11; -+ coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:12:12 - 12:17; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18; -+ coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2; ++ coverage Code(Counter(0)) => 10:1 - 10:11; ++ coverage Code(Expression(0)) => 12:12 - 12:17; ++ coverage Code(Counter(0)) => 13:13 - 13:18; ++ coverage Code(Counter(1)) => 14:9 - 14:10; ++ coverage Code(Counter(0)) => 16:1 - 16:2; + bb0: { + Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff index efb1559baf5eb..082539369f707 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff @@ -7,12 +7,13 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) + coverage body span: $DIR/instrument_coverage_cleanup.rs:13:11: 15:2 (#0) coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; - coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36; - coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39; - coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40; - coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2; - coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; + coverage Code(Counter(0)) => 13:1 - 14:36; + coverage Code(Expression(0)) => 14:37 - 14:39; + coverage Code(Counter(1)) => 14:38 - 14:39; + coverage Code(Counter(0)) => 15:1 - 15:2; + coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36; bb0: { Coverage::CounterIncrement(0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff index a0fe9a5c05cd1..8635818c6a7a1 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff @@ -7,12 +7,13 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) ++ coverage body span: $DIR/instrument_coverage_cleanup.rs:13:11: 15:2 (#0) + coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) }; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36; -+ coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39; -+ coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40; -+ coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2; -+ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36; ++ coverage Code(Counter(0)) => 13:1 - 14:36; ++ coverage Code(Expression(0)) => 14:37 - 14:39; ++ coverage Code(Counter(1)) => 14:38 - 14:39; ++ coverage Code(Counter(0)) => 15:1 - 15:2; ++ coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36; + bb0: { + Coverage::CounterIncrement(0);