mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #136809 - workingjubilee:rollup-jk0pew1, r=workingjubilee
Rollup of 12 pull requests Successful merges: - #136053 (coverage: Defer part of counter-creation until codegen) - #136201 (Removed dependency on the field-offset crate, alternate approach) - #136228 (Simplify Rc::as_ptr docs + typo fix) - #136353 (fix(libtest): Enable Instant on Emscripten targets) - #136472 ([`compiletest`-related cleanups 2/7] Feed stage number to compiletest directly) - #136487 (ci: stop mysql before removing it) - #136552 (Use an `Option` for `FindNextFileHandle` in `ReadDir` instead of `INVALID_FILE_HANDLE` sentinel value) - #136705 (Some miscellaneous edition-related library tweaks) - #136707 (Bump `cc` to v1.2.13 for the compiler workspace) - #136790 (Git blame ignore recent formatting commit) - #136792 (Don't apply editorconfig to llvm) - #136805 (ignore win_delete_self test in Miri) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -9,6 +9,8 @@ end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[!src/llvm-project]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
|
||||
@@ -29,3 +29,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8
|
||||
99cb0c6bc399fb94a0ddde7e9b38e9c00d523bad
|
||||
# reformat with rustfmt edition 2024
|
||||
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
|
||||
# reformat with updated edition 2024
|
||||
1fcae03369abb4c2cc180cd5a49e1f4440a81300
|
||||
|
||||
+2
-23
@@ -420,9 +420,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.7"
|
||||
version = "1.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
|
||||
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -1209,16 +1209,6 @@ dependencies = [
|
||||
"tidy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "field-offset"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.25"
|
||||
@@ -2295,15 +2285,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@@ -4173,7 +4154,6 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"either",
|
||||
"field-offset",
|
||||
"gsgdt",
|
||||
"polonius-engine",
|
||||
"rustc-rayon-core",
|
||||
@@ -4421,7 +4401,6 @@ dependencies = [
|
||||
name = "rustc_query_impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"field-offset",
|
||||
"measureme",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
|
||||
};
|
||||
use rustc_middle::mir::coverage::{
|
||||
CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op,
|
||||
BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,
|
||||
MappingKind, Op,
|
||||
};
|
||||
use rustc_middle::ty::{Instance, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
@@ -53,7 +54,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
|
||||
let fn_cov_info = tcx.instance_mir(instance.def).function_coverage_info.as_deref()?;
|
||||
let ids_info = tcx.coverage_ids_info(instance.def)?;
|
||||
|
||||
let expressions = prepare_expressions(fn_cov_info, ids_info, is_used);
|
||||
let expressions = prepare_expressions(ids_info);
|
||||
|
||||
let mut covfun = CovfunRecord {
|
||||
mangled_function_name: tcx.symbol_name(instance).name,
|
||||
@@ -75,26 +76,14 @@ pub(crate) fn prepare_covfun_record<'tcx>(
|
||||
}
|
||||
|
||||
/// Convert the function's coverage-counter expressions into a form suitable for FFI.
|
||||
fn prepare_expressions(
|
||||
fn_cov_info: &FunctionCoverageInfo,
|
||||
ids_info: &CoverageIdsInfo,
|
||||
is_used: bool,
|
||||
) -> Vec<ffi::CounterExpression> {
|
||||
// If any counters or expressions were removed by MIR opts, replace their
|
||||
// terms with zero.
|
||||
let counter_for_term = |term| {
|
||||
if !is_used || ids_info.is_zero_term(term) {
|
||||
ffi::Counter::ZERO
|
||||
} else {
|
||||
ffi::Counter::from_term(term)
|
||||
}
|
||||
};
|
||||
fn prepare_expressions(ids_info: &CoverageIdsInfo) -> Vec<ffi::CounterExpression> {
|
||||
let counter_for_term = ffi::Counter::from_term;
|
||||
|
||||
// We know that LLVM will optimize out any unused expressions before
|
||||
// producing the final coverage map, so there's no need to do the same
|
||||
// thing on the Rust side unless we're confident we can do much better.
|
||||
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
|
||||
fn_cov_info
|
||||
ids_info
|
||||
.expressions
|
||||
.iter()
|
||||
.map(move |&Expression { lhs, op, rhs }| ffi::CounterExpression {
|
||||
@@ -136,11 +125,16 @@ fn fill_region_tables<'tcx>(
|
||||
|
||||
// For each counter/region pair in this function+file, convert it to a
|
||||
// form suitable for FFI.
|
||||
let is_zero_term = |term| !covfun.is_used || ids_info.is_zero_term(term);
|
||||
for &Mapping { ref kind, span } in &fn_cov_info.mappings {
|
||||
// If the mapping refers to counters/expressions that were removed by
|
||||
// MIR opts, replace those occurrences with zero.
|
||||
let kind = kind.map_terms(|term| if is_zero_term(term) { CovTerm::Zero } else { term });
|
||||
// If this function is unused, replace all counters with zero.
|
||||
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
|
||||
let term = if covfun.is_used {
|
||||
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
|
||||
} else {
|
||||
CovTerm::Zero
|
||||
};
|
||||
ffi::Counter::from_term(term)
|
||||
};
|
||||
|
||||
// Convert the `Span` into coordinates that we can pass to LLVM, or
|
||||
// discard the span if conversion fails. In rare, cases _all_ of a
|
||||
@@ -154,23 +148,22 @@ fn fill_region_tables<'tcx>(
|
||||
continue;
|
||||
}
|
||||
|
||||
match kind {
|
||||
MappingKind::Code(term) => {
|
||||
code_regions
|
||||
.push(ffi::CodeRegion { cov_span, counter: ffi::Counter::from_term(term) });
|
||||
match *kind {
|
||||
MappingKind::Code { bcb } => {
|
||||
code_regions.push(ffi::CodeRegion { cov_span, counter: counter_for_bcb(bcb) });
|
||||
}
|
||||
MappingKind::Branch { true_term, false_term } => {
|
||||
MappingKind::Branch { true_bcb, false_bcb } => {
|
||||
branch_regions.push(ffi::BranchRegion {
|
||||
cov_span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
true_counter: counter_for_bcb(true_bcb),
|
||||
false_counter: counter_for_bcb(false_bcb),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
|
||||
MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params } => {
|
||||
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
|
||||
cov_span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
true_counter: counter_for_bcb(true_bcb),
|
||||
false_counter: counter_for_bcb(false_bcb),
|
||||
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -160,21 +160,12 @@ fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
|
||||
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
|
||||
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
|
||||
),
|
||||
CoverageKind::CounterIncrement { id } => {
|
||||
// The number of counters passed to `llvm.instrprof.increment` might
|
||||
// be smaller than the number originally inserted by the instrumentor,
|
||||
// if some high-numbered counters were removed by MIR optimizations.
|
||||
// If so, LLVM's profiler runtime will use fewer physical counters.
|
||||
let num_counters = ids_info.num_counters_after_mir_opts();
|
||||
assert!(
|
||||
num_counters as usize <= function_coverage_info.num_counters,
|
||||
"num_counters disagreement: query says {num_counters} but function info only has {}",
|
||||
function_coverage_info.num_counters
|
||||
);
|
||||
|
||||
CoverageKind::VirtualCounter { bcb }
|
||||
if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
|
||||
{
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
let num_counters = bx.const_u32(num_counters);
|
||||
let num_counters = bx.const_u32(ids_info.num_counters);
|
||||
let index = bx.const_u32(id.as_u32());
|
||||
debug!(
|
||||
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
|
||||
@@ -182,10 +173,8 @@ fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
|
||||
);
|
||||
bx.instrprof_increment(fn_name, hash, num_counters, index);
|
||||
}
|
||||
CoverageKind::ExpressionUsed { id: _ } => {
|
||||
// Expression-used statements are markers that are handled by
|
||||
// `coverage_ids_info`, so there's nothing to codegen here.
|
||||
}
|
||||
// If a BCB doesn't have an associated physical counter, there's nothing to codegen.
|
||||
CoverageKind::VirtualCounter { .. } => {}
|
||||
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
|
||||
let cond_bitmap = coverage_cx
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#![feature(extern_types)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_chains)]
|
||||
|
||||
@@ -11,7 +11,7 @@ bitflags = "2.4.1"
|
||||
bstr = "1.11.3"
|
||||
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
|
||||
# `cc` in `rustc_llvm` if you update the `cc` here.
|
||||
cc = "=1.2.7"
|
||||
cc = "=1.2.13"
|
||||
either = "1.5.0"
|
||||
itertools = "0.12"
|
||||
pathdiff = "0.2.0"
|
||||
|
||||
@@ -12,5 +12,5 @@ libc = "0.2.73"
|
||||
# tidy-alphabetical-start
|
||||
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
|
||||
# pinned `cc` in `rustc_codegen_ssa` if you update `cc` here.
|
||||
cc = "=1.2.7"
|
||||
cc = "=1.2.13"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
@@ -7,7 +7,6 @@ edition = "2021"
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
either = "1.5.0"
|
||||
field-offset = "0.3.5"
|
||||
gsgdt = "0.1.2"
|
||||
polonius-engine = "0.13.0"
|
||||
rustc-rayon-core = { version = "0.5.0" }
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_span::Span;
|
||||
|
||||
@@ -103,23 +103,12 @@ pub enum CoverageKind {
|
||||
/// Should be erased before codegen (at some point after `InstrumentCoverage`).
|
||||
BlockMarker { id: BlockMarkerId },
|
||||
|
||||
/// Marks the point in MIR control flow represented by a coverage counter.
|
||||
/// Marks its enclosing basic block with the ID of the coverage graph node
|
||||
/// that it was part of during the `InstrumentCoverage` MIR pass.
|
||||
///
|
||||
/// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR.
|
||||
///
|
||||
/// If this statement does not survive MIR optimizations, any mappings that
|
||||
/// refer to this counter can have those references simplified to zero.
|
||||
CounterIncrement { id: CounterId },
|
||||
|
||||
/// Marks the point in MIR control-flow represented by a coverage expression.
|
||||
///
|
||||
/// If this statement does not survive MIR optimizations, any mappings that
|
||||
/// refer to this expression can have those references simplified to zero.
|
||||
///
|
||||
/// (This is only inserted for expression IDs that are directly used by
|
||||
/// mappings. Intermediate expressions with no direct mappings are
|
||||
/// retained/zeroed based on whether they are transitively used.)
|
||||
ExpressionUsed { id: ExpressionId },
|
||||
/// During codegen, this might be lowered to `llvm.instrprof.increment` or
|
||||
/// to a no-op, depending on the outcome of counter-creation.
|
||||
VirtualCounter { bcb: BasicCoverageBlock },
|
||||
|
||||
/// Marks the point in MIR control flow represented by a evaluated condition.
|
||||
///
|
||||
@@ -138,8 +127,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
SpanMarker => write!(fmt, "SpanMarker"),
|
||||
BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()),
|
||||
CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()),
|
||||
ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()),
|
||||
VirtualCounter { bcb } => write!(fmt, "VirtualCounter({bcb:?})"),
|
||||
CondBitmapUpdate { index, decision_depth } => {
|
||||
write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth)
|
||||
}
|
||||
@@ -179,34 +167,19 @@ pub struct Expression {
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub enum MappingKind {
|
||||
/// Associates a normal region of code with a counter/expression/zero.
|
||||
Code(CovTerm),
|
||||
Code { bcb: BasicCoverageBlock },
|
||||
/// Associates a branch region with separate counters for true and false.
|
||||
Branch { true_term: CovTerm, false_term: CovTerm },
|
||||
Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock },
|
||||
/// Associates a branch region with separate counters for true and false.
|
||||
MCDCBranch { true_term: CovTerm, false_term: CovTerm, mcdc_params: ConditionInfo },
|
||||
MCDCBranch {
|
||||
true_bcb: BasicCoverageBlock,
|
||||
false_bcb: BasicCoverageBlock,
|
||||
mcdc_params: ConditionInfo,
|
||||
},
|
||||
/// Associates a decision region with a bitmap and number of conditions.
|
||||
MCDCDecision(DecisionInfo),
|
||||
}
|
||||
|
||||
impl MappingKind {
|
||||
/// Returns a copy of this mapping kind, in which all coverage terms have
|
||||
/// been replaced with ones returned by the given function.
|
||||
pub fn map_terms(&self, map_fn: impl Fn(CovTerm) -> CovTerm) -> Self {
|
||||
match *self {
|
||||
Self::Code(term) => Self::Code(map_fn(term)),
|
||||
Self::Branch { true_term, false_term } => {
|
||||
Self::Branch { true_term: map_fn(true_term), false_term: map_fn(false_term) }
|
||||
}
|
||||
Self::MCDCBranch { true_term, false_term, mcdc_params } => Self::MCDCBranch {
|
||||
true_term: map_fn(true_term),
|
||||
false_term: map_fn(false_term),
|
||||
mcdc_params,
|
||||
},
|
||||
Self::MCDCDecision(param) => Self::MCDCDecision(param),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub struct Mapping {
|
||||
@@ -222,10 +195,15 @@ pub struct Mapping {
|
||||
pub struct FunctionCoverageInfo {
|
||||
pub function_source_hash: u64,
|
||||
pub body_span: Span,
|
||||
pub num_counters: usize,
|
||||
pub mcdc_bitmap_bits: usize,
|
||||
pub expressions: IndexVec<ExpressionId, Expression>,
|
||||
|
||||
/// Used in conjunction with `priority_list` to create physical counters
|
||||
/// and counter expressions, after MIR optimizations.
|
||||
pub node_flow_data: NodeFlowData<BasicCoverageBlock>,
|
||||
pub priority_list: Vec<BasicCoverageBlock>,
|
||||
|
||||
pub mappings: Vec<Mapping>,
|
||||
|
||||
pub mcdc_bitmap_bits: usize,
|
||||
/// The depth of the deepest decision is used to know how many
|
||||
/// temp condbitmaps should be allocated for the function.
|
||||
pub mcdc_num_condition_bitmaps: usize,
|
||||
@@ -292,40 +270,55 @@ pub struct MCDCDecisionSpan {
|
||||
pub num_conditions: usize,
|
||||
}
|
||||
|
||||
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
|
||||
/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
|
||||
/// have had a chance to potentially remove some of them.
|
||||
/// Contains information needed during codegen, obtained by inspecting the
|
||||
/// function's MIR after MIR optimizations.
|
||||
///
|
||||
/// Used by the `coverage_ids_info` query.
|
||||
/// Returned by the `coverage_ids_info` query.
|
||||
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
|
||||
pub struct CoverageIdsInfo {
|
||||
pub counters_seen: DenseBitSet<CounterId>,
|
||||
pub zero_expressions: DenseBitSet<ExpressionId>,
|
||||
pub num_counters: u32,
|
||||
pub phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>,
|
||||
pub term_for_bcb: IndexVec<BasicCoverageBlock, Option<CovTerm>>,
|
||||
pub expressions: IndexVec<ExpressionId, Expression>,
|
||||
}
|
||||
|
||||
impl CoverageIdsInfo {
|
||||
/// Coverage codegen needs to know how many coverage counters are ever
|
||||
/// incremented within a function, so that it can set the `num-counters`
|
||||
/// argument of the `llvm.instrprof.increment` intrinsic.
|
||||
rustc_index::newtype_index! {
|
||||
/// During the `InstrumentCoverage` MIR pass, a BCB is a node in the
|
||||
/// "coverage graph", which is a refinement of the MIR control-flow graph
|
||||
/// that merges or omits some blocks that aren't relevant to coverage.
|
||||
///
|
||||
/// This may be less than the highest counter ID emitted by the
|
||||
/// InstrumentCoverage MIR pass, if the highest-numbered counter increments
|
||||
/// were removed by MIR optimizations.
|
||||
pub fn num_counters_after_mir_opts(&self) -> u32 {
|
||||
// FIXME(Zalathar): Currently this treats an unused counter as "used"
|
||||
// if its ID is less than that of the highest counter that really is
|
||||
// used. Fixing this would require adding a renumbering step somewhere.
|
||||
self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1)
|
||||
}
|
||||
|
||||
/// Returns `true` if the given term is known to have a value of zero, taking
|
||||
/// into account knowledge of which counters are unused and which expressions
|
||||
/// are always zero.
|
||||
pub fn is_zero_term(&self, term: CovTerm) -> bool {
|
||||
match term {
|
||||
CovTerm::Zero => true,
|
||||
CovTerm::Counter(id) => !self.counters_seen.contains(id),
|
||||
CovTerm::Expression(id) => self.zero_expressions.contains(id),
|
||||
}
|
||||
/// After that pass is complete, the coverage graph no longer exists, so a
|
||||
/// BCB is effectively an opaque ID.
|
||||
#[derive(HashStable)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[debug_format = "bcb{}"]
|
||||
pub struct BasicCoverageBlock {
|
||||
const START_BCB = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Data representing a view of some underlying graph, in which each node's
|
||||
/// successors have been merged into a single "supernode".
|
||||
///
|
||||
/// The resulting supernodes have no obvious meaning on their own.
|
||||
/// However, merging successor nodes means that a node's out-edges can all
|
||||
/// be combined into a single out-edge, whose flow is the same as the flow
|
||||
/// (execution count) of its corresponding node in the original graph.
|
||||
///
|
||||
/// With all node flows now in the original graph now represented as edge flows
|
||||
/// in the merged graph, it becomes possible to analyze the original node flows
|
||||
/// using techniques for analyzing edge flows.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub struct NodeFlowData<Node: Idx> {
|
||||
/// Maps each node to the supernode that contains it, indicated by some
|
||||
/// arbitrary "root" node that is part of that supernode.
|
||||
pub supernodes: IndexVec<Node, Node>,
|
||||
/// For each node, stores the single supernode that all of its successors
|
||||
/// have been merged into.
|
||||
///
|
||||
/// (Note that each node in a supernode can potentially have a _different_
|
||||
/// successor supernode from its peers.)
|
||||
pub succ_supernodes: IndexVec<Node, Node>,
|
||||
}
|
||||
|
||||
@@ -619,13 +619,9 @@ fn write_function_coverage_info(
|
||||
function_coverage_info: &coverage::FunctionCoverageInfo,
|
||||
w: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
let coverage::FunctionCoverageInfo { body_span, expressions, mappings, .. } =
|
||||
function_coverage_info;
|
||||
let coverage::FunctionCoverageInfo { body_span, 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:?};")?;
|
||||
}
|
||||
for coverage::Mapping { kind, span } in mappings {
|
||||
writeln!(w, "{INDENT}coverage {kind:?} => {span:?};")?;
|
||||
}
|
||||
|
||||
@@ -614,9 +614,16 @@
|
||||
feedable
|
||||
}
|
||||
|
||||
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
|
||||
/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
|
||||
/// have had a chance to potentially remove some of them.
|
||||
/// Scans through a function's MIR after MIR optimizations, to prepare the
|
||||
/// information needed by codegen when `-Cinstrument-coverage` is active.
|
||||
///
|
||||
/// This includes the details of where to insert `llvm.instrprof.increment`
|
||||
/// intrinsics, and the expression tables to be embedded in the function's
|
||||
/// coverage metadata.
|
||||
///
|
||||
/// FIXME(Zalathar): This query's purpose has drifted a bit and should
|
||||
/// probably be renamed, but that can wait until after the potential
|
||||
/// follow-ups to #136053 have settled down.
|
||||
///
|
||||
/// Returns `None` for functions that were not instrumented.
|
||||
query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> Option<&'tcx mir::coverage::CoverageIdsInfo> {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use field_offset::FieldOffset;
|
||||
use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::hir_id::OwnerId;
|
||||
@@ -24,8 +23,10 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
|
||||
pub eval_always: bool,
|
||||
pub dep_kind: DepKind,
|
||||
pub handle_cycle_error: HandleCycleError,
|
||||
pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key>>,
|
||||
pub query_cache: FieldOffset<QueryCaches<'tcx>, C>,
|
||||
// Offset of this query's state field in the QueryStates struct
|
||||
pub query_state: usize,
|
||||
// Offset of this query's cache field in the QueryCaches struct
|
||||
pub query_cache: usize,
|
||||
pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
|
||||
pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
|
||||
pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
use either::Either;
|
||||
use itertools::Itertools;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::graph::DirectedGraph;
|
||||
use rustc_index::IndexVec;
|
||||
@@ -11,31 +10,35 @@
|
||||
|
||||
use crate::coverage::counters::balanced_flow::BalancedFlowGraph;
|
||||
use crate::coverage::counters::node_flow::{
|
||||
CounterTerm, NodeCounters, make_node_counters, node_flow_data_for_balanced_graph,
|
||||
CounterTerm, NodeCounters, NodeFlowData, node_flow_data_for_balanced_graph,
|
||||
};
|
||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
|
||||
|
||||
mod balanced_flow;
|
||||
mod node_flow;
|
||||
pub(crate) mod node_flow;
|
||||
mod union_find;
|
||||
|
||||
/// Ensures that each BCB node needing a counter has one, by creating physical
|
||||
/// counters or counter expressions for nodes as required.
|
||||
pub(super) fn make_bcb_counters(
|
||||
graph: &CoverageGraph,
|
||||
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
|
||||
) -> CoverageCounters {
|
||||
/// Struct containing the results of [`prepare_bcb_counters_data`].
|
||||
pub(crate) struct BcbCountersData {
|
||||
pub(crate) node_flow_data: NodeFlowData<BasicCoverageBlock>,
|
||||
pub(crate) priority_list: Vec<BasicCoverageBlock>,
|
||||
}
|
||||
|
||||
/// Analyzes the coverage graph to create intermediate data structures that
|
||||
/// will later be used (during codegen) to create physical counters or counter
|
||||
/// expressions for each BCB node that needs one.
|
||||
pub(crate) fn prepare_bcb_counters_data(graph: &CoverageGraph) -> BcbCountersData {
|
||||
// Create the derived graphs that are necessary for subsequent steps.
|
||||
let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable);
|
||||
let node_flow_data = node_flow_data_for_balanced_graph(&balanced_graph);
|
||||
|
||||
// Use those graphs to determine which nodes get physical counters, and how
|
||||
// to compute the execution counts of other nodes from those counters.
|
||||
// Also create a "priority list" of coverage graph nodes, to help determine
|
||||
// which ones get physical counters or counter expressions. This needs to
|
||||
// be done now, because the later parts of the counter-creation process
|
||||
// won't have access to the original coverage graph.
|
||||
let priority_list = make_node_flow_priority_list(graph, balanced_graph);
|
||||
let node_counters = make_node_counters(&node_flow_data, &priority_list);
|
||||
|
||||
// Convert the counters into a form suitable for embedding into MIR.
|
||||
transcribe_counters(&node_counters, bcb_needs_counter)
|
||||
BcbCountersData { node_flow_data, priority_list }
|
||||
}
|
||||
|
||||
/// Arranges the nodes in `balanced_graph` into a list, such that earlier nodes
|
||||
@@ -74,31 +77,33 @@ fn make_node_flow_priority_list(
|
||||
}
|
||||
|
||||
// Converts node counters into a form suitable for embedding into MIR.
|
||||
fn transcribe_counters(
|
||||
pub(crate) fn transcribe_counters(
|
||||
old: &NodeCounters<BasicCoverageBlock>,
|
||||
bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>,
|
||||
bcbs_seen: &DenseBitSet<BasicCoverageBlock>,
|
||||
) -> CoverageCounters {
|
||||
let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size());
|
||||
|
||||
for bcb in bcb_needs_counter.iter() {
|
||||
if !bcbs_seen.contains(bcb) {
|
||||
// This BCB's code was removed by MIR opts, so its counter is always zero.
|
||||
new.set_node_counter(bcb, CovTerm::Zero);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Our counter-creation algorithm doesn't guarantee that a node's list
|
||||
// of terms starts or ends with a positive term, so partition the
|
||||
// counters into "positive" and "negative" lists for easier handling.
|
||||
let (mut pos, mut neg): (Vec<_>, Vec<_>) =
|
||||
old.counter_terms[bcb].iter().partition_map(|&CounterTerm { node, op }| match op {
|
||||
let (mut pos, mut neg): (Vec<_>, Vec<_>) = old.counter_terms[bcb]
|
||||
.iter()
|
||||
// Filter out any BCBs that were removed by MIR opts;
|
||||
// this treats them as having an execution count of 0.
|
||||
.filter(|term| bcbs_seen.contains(term.node))
|
||||
.partition_map(|&CounterTerm { node, op }| match op {
|
||||
Op::Add => Either::Left(node),
|
||||
Op::Subtract => Either::Right(node),
|
||||
});
|
||||
|
||||
if pos.is_empty() {
|
||||
// If we somehow end up with no positive terms, fall back to
|
||||
// creating a physical counter. There's no known way for this
|
||||
// to happen, but we can avoid an ICE if it does.
|
||||
debug_assert!(false, "{bcb:?} has no positive counter terms");
|
||||
pos = vec![bcb];
|
||||
neg = vec![];
|
||||
}
|
||||
|
||||
// These intermediate sorts are not strictly necessary, but were helpful
|
||||
// in reducing churn when switching to the current counter-creation scheme.
|
||||
// They also help to slightly decrease the overall size of the expression
|
||||
@@ -116,7 +121,7 @@ fn transcribe_counters(
|
||||
pos.sort();
|
||||
neg.sort();
|
||||
|
||||
let pos_counter = new.make_sum(&pos).expect("`pos` should not be empty");
|
||||
let pos_counter = new.make_sum(&pos).unwrap_or(CovTerm::Zero);
|
||||
let new_counter = new.make_subtracted_sum(pos_counter, &neg);
|
||||
new.set_node_counter(bcb, new_counter);
|
||||
}
|
||||
@@ -129,15 +134,15 @@ fn transcribe_counters(
|
||||
pub(super) struct CoverageCounters {
|
||||
/// List of places where a counter-increment statement should be injected
|
||||
/// into MIR, each with its corresponding counter ID.
|
||||
phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>,
|
||||
next_counter_id: CounterId,
|
||||
pub(crate) phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>,
|
||||
pub(crate) next_counter_id: CounterId,
|
||||
|
||||
/// Coverage counters/expressions that are associated with individual BCBs.
|
||||
node_counters: IndexVec<BasicCoverageBlock, Option<CovTerm>>,
|
||||
pub(crate) node_counters: IndexVec<BasicCoverageBlock, Option<CovTerm>>,
|
||||
|
||||
/// Table of expression data, associating each expression ID with its
|
||||
/// corresponding operator (+ or -) and its LHS/RHS operands.
|
||||
expressions: IndexVec<ExpressionId, Expression>,
|
||||
pub(crate) expressions: IndexVec<ExpressionId, Expression>,
|
||||
/// Remember expressions that have already been created (or simplified),
|
||||
/// so that we don't create unnecessary duplicates.
|
||||
expressions_memo: FxHashMap<Expression, CovTerm>,
|
||||
@@ -188,12 +193,6 @@ fn make_subtracted_sum(&mut self, lhs: CovTerm, rhs: &[CovTerm]) -> CovTerm {
|
||||
self.make_expression(lhs, Op::Subtract, rhs_sum)
|
||||
}
|
||||
|
||||
pub(super) fn num_counters(&self) -> usize {
|
||||
let num_counters = self.phys_counter_for_node.len();
|
||||
assert_eq!(num_counters, self.next_counter_id.as_usize());
|
||||
num_counters
|
||||
}
|
||||
|
||||
fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: CovTerm) -> CovTerm {
|
||||
let existing = self.node_counters[bcb].replace(counter);
|
||||
assert!(
|
||||
@@ -202,34 +201,4 @@ fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: CovTerm) -> Cov
|
||||
);
|
||||
counter
|
||||
}
|
||||
|
||||
pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> {
|
||||
self.node_counters[bcb]
|
||||
}
|
||||
|
||||
/// Returns an iterator over all the nodes in the coverage graph that
|
||||
/// should have a counter-increment statement injected into MIR, along with
|
||||
/// each site's corresponding counter ID.
|
||||
pub(super) fn counter_increment_sites(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (CounterId, BasicCoverageBlock)> + Captures<'_> {
|
||||
self.phys_counter_for_node.iter().map(|(&site, &id)| (id, site))
|
||||
}
|
||||
|
||||
/// Returns an iterator over the subset of BCB nodes that have been associated
|
||||
/// with a counter *expression*, along with the ID of that expression.
|
||||
pub(super) fn bcb_nodes_with_coverage_expressions(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (BasicCoverageBlock, ExpressionId)> + Captures<'_> {
|
||||
self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter {
|
||||
// Yield the BCB along with its associated expression ID.
|
||||
Some(CovTerm::Expression(id)) => Some((bcb, id)),
|
||||
// This BCB is associated with a counter or nothing, so skip it.
|
||||
Some(CovTerm::Counter { .. } | CovTerm::Zero) | None => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
|
||||
self.expressions
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
pub(crate) use rustc_middle::mir::coverage::NodeFlowData;
|
||||
use rustc_middle::mir::coverage::Op;
|
||||
|
||||
use crate::coverage::counters::union_find::UnionFind;
|
||||
@@ -16,30 +17,6 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// Data representing a view of some underlying graph, in which each node's
|
||||
/// successors have been merged into a single "supernode".
|
||||
///
|
||||
/// The resulting supernodes have no obvious meaning on their own.
|
||||
/// However, merging successor nodes means that a node's out-edges can all
|
||||
/// be combined into a single out-edge, whose flow is the same as the flow
|
||||
/// (execution count) of its corresponding node in the original graph.
|
||||
///
|
||||
/// With all node flows now in the original graph now represented as edge flows
|
||||
/// in the merged graph, it becomes possible to analyze the original node flows
|
||||
/// using techniques for analyzing edge flows.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct NodeFlowData<Node: Idx> {
|
||||
/// Maps each node to the supernode that contains it, indicated by some
|
||||
/// arbitrary "root" node that is part of that supernode.
|
||||
supernodes: IndexVec<Node, Node>,
|
||||
/// For each node, stores the single supernode that all of its successors
|
||||
/// have been merged into.
|
||||
///
|
||||
/// (Note that each node in a supernode can potentially have a _different_
|
||||
/// successor supernode from its peers.)
|
||||
succ_supernodes: IndexVec<Node, Node>,
|
||||
}
|
||||
|
||||
/// Creates a "merged" view of an underlying graph.
|
||||
///
|
||||
/// The given graph is assumed to have [“balanced flow”](balanced-flow),
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
pub(crate) use rustc_middle::mir::coverage::{BasicCoverageBlock, START_BCB};
|
||||
use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
|
||||
use tracing::debug;
|
||||
|
||||
@@ -269,15 +270,6 @@ fn predecessors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A node in the control-flow graph of CoverageGraph.
|
||||
#[orderable]
|
||||
#[debug_format = "bcb{}"]
|
||||
pub(crate) struct BasicCoverageBlock {
|
||||
const START_BCB = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// `BasicCoverageBlockData` holds the data indexed by a `BasicCoverageBlock`.
|
||||
///
|
||||
/// A `BasicCoverageBlock` (BCB) represents the maximal-length sequence of MIR `BasicBlock`s without
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph::DirectedGraph;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::mir::coverage::{
|
||||
BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageInfoHi, CoverageKind,
|
||||
};
|
||||
@@ -63,10 +61,6 @@ pub(super) struct MCDCDecision {
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct ExtractedMappings {
|
||||
/// Store our own copy of [`CoverageGraph::num_nodes`], so that we don't
|
||||
/// need access to the whole graph when allocating per-BCB data. This is
|
||||
/// only public so that other code can still use exhaustive destructuring.
|
||||
pub(super) num_bcbs: usize,
|
||||
pub(super) code_mappings: Vec<CodeMapping>,
|
||||
pub(super) branch_pairs: Vec<BranchPair>,
|
||||
pub(super) mcdc_bitmap_bits: usize,
|
||||
@@ -118,7 +112,6 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
|
||||
);
|
||||
|
||||
ExtractedMappings {
|
||||
num_bcbs: graph.num_nodes(),
|
||||
code_mappings,
|
||||
branch_pairs,
|
||||
mcdc_bitmap_bits,
|
||||
@@ -127,60 +120,6 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractedMappings {
|
||||
pub(super) fn all_bcbs_with_counter_mappings(&self) -> DenseBitSet<BasicCoverageBlock> {
|
||||
// Fully destructure self to make sure we don't miss any fields that have mappings.
|
||||
let Self {
|
||||
num_bcbs,
|
||||
code_mappings,
|
||||
branch_pairs,
|
||||
mcdc_bitmap_bits: _,
|
||||
mcdc_degraded_branches,
|
||||
mcdc_mappings,
|
||||
} = self;
|
||||
|
||||
// Identify which BCBs have one or more mappings.
|
||||
let mut bcbs_with_counter_mappings = DenseBitSet::new_empty(*num_bcbs);
|
||||
let mut insert = |bcb| {
|
||||
bcbs_with_counter_mappings.insert(bcb);
|
||||
};
|
||||
|
||||
for &CodeMapping { span: _, bcb } in code_mappings {
|
||||
insert(bcb);
|
||||
}
|
||||
for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs {
|
||||
insert(true_bcb);
|
||||
insert(false_bcb);
|
||||
}
|
||||
for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_degraded_branches
|
||||
.iter()
|
||||
.chain(mcdc_mappings.iter().map(|(_, branches)| branches.into_iter()).flatten())
|
||||
{
|
||||
insert(true_bcb);
|
||||
insert(false_bcb);
|
||||
}
|
||||
|
||||
// MC/DC decisions refer to BCBs, but don't require those BCBs to have counters.
|
||||
if bcbs_with_counter_mappings.is_empty() {
|
||||
debug_assert!(
|
||||
mcdc_mappings.is_empty(),
|
||||
"A function with no counter mappings shouldn't have any decisions: {mcdc_mappings:?}",
|
||||
);
|
||||
}
|
||||
|
||||
bcbs_with_counter_mappings
|
||||
}
|
||||
|
||||
/// Returns the set of BCBs that have one or more `Code` mappings.
|
||||
pub(super) fn bcbs_with_ordinary_code_mappings(&self) -> DenseBitSet<BasicCoverageBlock> {
|
||||
let mut bcbs = DenseBitSet::new_empty(self.num_bcbs);
|
||||
for &CodeMapping { span: _, bcb } in &self.code_mappings {
|
||||
bcbs.insert(bcb);
|
||||
}
|
||||
bcbs
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_block_markers(
|
||||
coverage_info_hi: &CoverageInfoHi,
|
||||
mir_body: &mir::Body<'_>,
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use tracing::{debug, debug_span, trace};
|
||||
|
||||
use crate::coverage::counters::CoverageCounters;
|
||||
use crate::coverage::counters::BcbCountersData;
|
||||
use crate::coverage::graph::CoverageGraph;
|
||||
use crate::coverage::mappings::ExtractedMappings;
|
||||
|
||||
@@ -82,28 +82,21 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
||||
let extracted_mappings =
|
||||
mappings::extract_all_mapping_info_from_mir(tcx, mir_body, &hir_info, &graph);
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
|
||||
// every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
|
||||
// and all `Expression` dependencies (operands) are also generated, for any other
|
||||
// `BasicCoverageBlock`s not already associated with a coverage span.
|
||||
let bcbs_with_counter_mappings = extracted_mappings.all_bcbs_with_counter_mappings();
|
||||
if bcbs_with_counter_mappings.is_empty() {
|
||||
// No relevant spans were found in MIR, so skip instrumenting this function.
|
||||
return;
|
||||
}
|
||||
|
||||
let coverage_counters = counters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
|
||||
|
||||
let mappings = create_mappings(&extracted_mappings, &coverage_counters);
|
||||
let mappings = create_mappings(&extracted_mappings);
|
||||
if mappings.is_empty() {
|
||||
// No spans could be converted into valid mappings, so skip this function.
|
||||
debug!("no spans could be converted into valid mappings; skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
inject_coverage_statements(mir_body, &graph, &extracted_mappings, &coverage_counters);
|
||||
// Use the coverage graph to prepare intermediate data that will eventually
|
||||
// be used to assign physical counters and counter expressions to points in
|
||||
// the control-flow graph
|
||||
let BcbCountersData { node_flow_data, priority_list } =
|
||||
counters::prepare_bcb_counters_data(&graph);
|
||||
|
||||
// Inject coverage statements into MIR.
|
||||
inject_coverage_statements(mir_body, &graph);
|
||||
inject_mcdc_statements(mir_body, &graph, &extracted_mappings);
|
||||
|
||||
let mcdc_num_condition_bitmaps = extracted_mappings
|
||||
@@ -116,29 +109,25 @@ 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(),
|
||||
|
||||
node_flow_data,
|
||||
priority_list,
|
||||
|
||||
mappings,
|
||||
|
||||
mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits,
|
||||
mcdc_num_condition_bitmaps,
|
||||
}));
|
||||
}
|
||||
|
||||
/// For each coverage span extracted from MIR, create a corresponding
|
||||
/// mapping.
|
||||
/// For each coverage span extracted from MIR, create a corresponding mapping.
|
||||
///
|
||||
/// Precondition: All BCBs corresponding to those spans have been given
|
||||
/// coverage counters.
|
||||
fn create_mappings(
|
||||
extracted_mappings: &ExtractedMappings,
|
||||
coverage_counters: &CoverageCounters,
|
||||
) -> Vec<Mapping> {
|
||||
let term_for_bcb =
|
||||
|bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
|
||||
|
||||
/// FIXME(Zalathar): This used to be where BCBs in the extracted mappings were
|
||||
/// resolved to a `CovTerm`. But that is now handled elsewhere, so this
|
||||
/// function can potentially be simplified even further.
|
||||
fn create_mappings(extracted_mappings: &ExtractedMappings) -> Vec<Mapping> {
|
||||
// Fully destructure the mappings struct to make sure we don't miss any kinds.
|
||||
let ExtractedMappings {
|
||||
num_bcbs: _,
|
||||
code_mappings,
|
||||
branch_pairs,
|
||||
mcdc_bitmap_bits: _,
|
||||
@@ -150,23 +139,18 @@ fn create_mappings(
|
||||
mappings.extend(code_mappings.iter().map(
|
||||
// Ordinary code mappings are the simplest kind.
|
||||
|&mappings::CodeMapping { span, bcb }| {
|
||||
let kind = MappingKind::Code(term_for_bcb(bcb));
|
||||
let kind = MappingKind::Code { bcb };
|
||||
Mapping { kind, span }
|
||||
},
|
||||
));
|
||||
|
||||
mappings.extend(branch_pairs.iter().map(
|
||||
|&mappings::BranchPair { span, true_bcb, false_bcb }| {
|
||||
let true_term = term_for_bcb(true_bcb);
|
||||
let false_term = term_for_bcb(false_bcb);
|
||||
let kind = MappingKind::Branch { true_term, false_term };
|
||||
let kind = MappingKind::Branch { true_bcb, false_bcb };
|
||||
Mapping { kind, span }
|
||||
},
|
||||
));
|
||||
|
||||
let term_for_bcb =
|
||||
|bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
|
||||
|
||||
// MCDC branch mappings are appended with their decisions in case decisions were ignored.
|
||||
mappings.extend(mcdc_degraded_branches.iter().map(
|
||||
|&mappings::MCDCBranch {
|
||||
@@ -176,11 +160,7 @@ fn create_mappings(
|
||||
condition_info: _,
|
||||
true_index: _,
|
||||
false_index: _,
|
||||
}| {
|
||||
let true_term = term_for_bcb(true_bcb);
|
||||
let false_term = term_for_bcb(false_bcb);
|
||||
Mapping { kind: MappingKind::Branch { true_term, false_term }, span }
|
||||
},
|
||||
}| { Mapping { kind: MappingKind::Branch { true_bcb, false_bcb }, span } },
|
||||
));
|
||||
|
||||
for (decision, branches) in mcdc_mappings {
|
||||
@@ -201,12 +181,10 @@ fn create_mappings(
|
||||
true_index: _,
|
||||
false_index: _,
|
||||
}| {
|
||||
let true_term = term_for_bcb(true_bcb);
|
||||
let false_term = term_for_bcb(false_bcb);
|
||||
Mapping {
|
||||
kind: MappingKind::MCDCBranch {
|
||||
true_term,
|
||||
false_term,
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
mcdc_params: condition_info,
|
||||
},
|
||||
span,
|
||||
@@ -227,41 +205,11 @@ fn create_mappings(
|
||||
mappings
|
||||
}
|
||||
|
||||
/// For each BCB node or BCB edge that has an associated coverage counter,
|
||||
/// inject any necessary coverage statements into MIR.
|
||||
fn inject_coverage_statements<'tcx>(
|
||||
mir_body: &mut mir::Body<'tcx>,
|
||||
graph: &CoverageGraph,
|
||||
extracted_mappings: &ExtractedMappings,
|
||||
coverage_counters: &CoverageCounters,
|
||||
) {
|
||||
// Inject counter-increment statements into MIR.
|
||||
for (id, bcb) in coverage_counters.counter_increment_sites() {
|
||||
let target_bb = graph[bcb].leader_bb();
|
||||
inject_statement(mir_body, CoverageKind::CounterIncrement { id }, target_bb);
|
||||
}
|
||||
|
||||
// For each counter expression that is directly associated with at least one
|
||||
// span, we inject an "expression-used" statement, so that coverage codegen
|
||||
// can check whether the injected statement survived MIR optimization.
|
||||
// (BCB edges can't have spans, so we only need to process BCB nodes here.)
|
||||
//
|
||||
// We only do this for ordinary `Code` mappings, because branch and MC/DC
|
||||
// mappings might have expressions that don't correspond to any single
|
||||
// point in the control-flow graph.
|
||||
//
|
||||
// See the code in `rustc_codegen_llvm::coverageinfo::map_data` that deals
|
||||
// with "expressions seen" and "zero terms".
|
||||
let eligible_bcbs = extracted_mappings.bcbs_with_ordinary_code_mappings();
|
||||
for (bcb, expression_id) in coverage_counters
|
||||
.bcb_nodes_with_coverage_expressions()
|
||||
.filter(|&(bcb, _)| eligible_bcbs.contains(bcb))
|
||||
{
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::ExpressionUsed { id: expression_id },
|
||||
graph[bcb].leader_bb(),
|
||||
);
|
||||
/// Inject any necessary coverage statements into MIR, so that they influence codegen.
|
||||
fn inject_coverage_statements<'tcx>(mir_body: &mut mir::Body<'tcx>, graph: &CoverageGraph) {
|
||||
for (bcb, data) in graph.iter_enumerated() {
|
||||
let target_bb = data.leader_bb();
|
||||
inject_statement(mir_body, CoverageKind::VirtualCounter { bcb }, target_bb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CounterId, CovTerm, CoverageIdsInfo, CoverageKind, Expression, ExpressionId,
|
||||
FunctionCoverageInfo, MappingKind, Op,
|
||||
};
|
||||
use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind};
|
||||
use rustc_middle::mir::{Body, Statement, StatementKind};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
@@ -12,6 +9,9 @@
|
||||
use rustc_span::sym;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::coverage::counters::node_flow::make_node_counters;
|
||||
use crate::coverage::counters::{CoverageCounters, transcribe_counters};
|
||||
|
||||
/// Registers query/hook implementations related to coverage.
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.hooks.is_eligible_for_coverage = is_eligible_for_coverage;
|
||||
@@ -89,39 +89,57 @@ fn coverage_ids_info<'tcx>(
|
||||
let mir_body = tcx.instance_mir(instance_def);
|
||||
let fn_cov_info = mir_body.function_coverage_info.as_deref()?;
|
||||
|
||||
let mut counters_seen = DenseBitSet::new_empty(fn_cov_info.num_counters);
|
||||
let mut expressions_seen = DenseBitSet::new_filled(fn_cov_info.expressions.len());
|
||||
|
||||
// For each expression ID that is directly used by one or more mappings,
|
||||
// mark it as not-yet-seen. This indicates that we expect to see a
|
||||
// corresponding `ExpressionUsed` statement during MIR traversal.
|
||||
for mapping in fn_cov_info.mappings.iter() {
|
||||
// Currently we only worry about ordinary code mappings.
|
||||
// For branch and MC/DC mappings, expressions might not correspond
|
||||
// to any particular point in the control-flow graph.
|
||||
// (Keep this in sync with the injection of `ExpressionUsed`
|
||||
// statements in the `InstrumentCoverage` MIR pass.)
|
||||
if let MappingKind::Code(CovTerm::Expression(id)) = mapping.kind {
|
||||
expressions_seen.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Scan through the final MIR to see which BCBs survived MIR opts.
|
||||
// Any BCB not in this set was optimized away.
|
||||
let mut bcbs_seen = DenseBitSet::new_empty(fn_cov_info.priority_list.len());
|
||||
for kind in all_coverage_in_mir_body(mir_body) {
|
||||
match *kind {
|
||||
CoverageKind::CounterIncrement { id } => {
|
||||
counters_seen.insert(id);
|
||||
}
|
||||
CoverageKind::ExpressionUsed { id } => {
|
||||
expressions_seen.insert(id);
|
||||
CoverageKind::VirtualCounter { bcb } => {
|
||||
bcbs_seen.insert(bcb);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let zero_expressions =
|
||||
identify_zero_expressions(fn_cov_info, &counters_seen, &expressions_seen);
|
||||
// Determine the set of BCBs that are referred to by mappings, and therefore
|
||||
// need a counter. Any node not in this set will only get a counter if it
|
||||
// is part of the counter expression for a node that is in the set.
|
||||
let mut bcb_needs_counter =
|
||||
DenseBitSet::<BasicCoverageBlock>::new_empty(fn_cov_info.priority_list.len());
|
||||
for mapping in &fn_cov_info.mappings {
|
||||
match mapping.kind {
|
||||
MappingKind::Code { bcb } => {
|
||||
bcb_needs_counter.insert(bcb);
|
||||
}
|
||||
MappingKind::Branch { true_bcb, false_bcb } => {
|
||||
bcb_needs_counter.insert(true_bcb);
|
||||
bcb_needs_counter.insert(false_bcb);
|
||||
}
|
||||
MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params: _ } => {
|
||||
bcb_needs_counter.insert(true_bcb);
|
||||
bcb_needs_counter.insert(false_bcb);
|
||||
}
|
||||
MappingKind::MCDCDecision(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
Some(CoverageIdsInfo { counters_seen, zero_expressions })
|
||||
// FIXME(Zalathar): It should be possible to sort `priority_list[1..]` by
|
||||
// `!bcbs_seen.contains(bcb)` to simplify the mappings even further, at the
|
||||
// expense of some churn in the tests. When doing so, also consider removing
|
||||
// the sorts in `transcribe_counters`.
|
||||
let node_counters = make_node_counters(&fn_cov_info.node_flow_data, &fn_cov_info.priority_list);
|
||||
let coverage_counters = transcribe_counters(&node_counters, &bcb_needs_counter, &bcbs_seen);
|
||||
|
||||
let CoverageCounters {
|
||||
phys_counter_for_node, next_counter_id, node_counters, expressions, ..
|
||||
} = coverage_counters;
|
||||
|
||||
Some(CoverageIdsInfo {
|
||||
num_counters: next_counter_id.as_u32(),
|
||||
phys_counter_for_node,
|
||||
term_for_bcb: node_counters,
|
||||
expressions,
|
||||
})
|
||||
}
|
||||
|
||||
fn all_coverage_in_mir_body<'a, 'tcx>(
|
||||
@@ -139,94 +157,3 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
|
||||
let scope_data = &body.source_scopes[statement.source_info.scope];
|
||||
scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some()
|
||||
}
|
||||
|
||||
/// Identify expressions that will always have a value of zero, and note their
|
||||
/// IDs in a `DenseBitSet`. Mappings that refer to a zero expression can instead
|
||||
/// become mappings to a constant zero value.
|
||||
///
|
||||
/// This function mainly exists to preserve the simplifications that were
|
||||
/// already being performed by the Rust-side expression renumbering, so that
|
||||
/// the resulting coverage mappings don't get worse.
|
||||
fn identify_zero_expressions(
|
||||
fn_cov_info: &FunctionCoverageInfo,
|
||||
counters_seen: &DenseBitSet<CounterId>,
|
||||
expressions_seen: &DenseBitSet<ExpressionId>,
|
||||
) -> DenseBitSet<ExpressionId> {
|
||||
// The set of expressions that either were optimized out entirely, or
|
||||
// have zero as both of their operands, and will therefore always have
|
||||
// a value of zero. Other expressions that refer to these as operands
|
||||
// can have those operands replaced with `CovTerm::Zero`.
|
||||
let mut zero_expressions = DenseBitSet::new_empty(fn_cov_info.expressions.len());
|
||||
|
||||
// Simplify a copy of each expression based on lower-numbered expressions,
|
||||
// and then update the set of always-zero expressions if necessary.
|
||||
// (By construction, expressions can only refer to other expressions
|
||||
// that have lower IDs, so one pass is sufficient.)
|
||||
for (id, expression) in fn_cov_info.expressions.iter_enumerated() {
|
||||
if !expressions_seen.contains(id) {
|
||||
// If an expression was not seen, it must have been optimized away,
|
||||
// so any operand that refers to it can be replaced with zero.
|
||||
zero_expressions.insert(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't need to simplify the actual expression data in the
|
||||
// expressions list; we can just simplify a temporary copy and then
|
||||
// use that to update the set of always-zero expressions.
|
||||
let Expression { mut lhs, op, mut rhs } = *expression;
|
||||
|
||||
// If an expression has an operand that is also an expression, the
|
||||
// operand's ID must be strictly lower. This is what lets us find
|
||||
// all zero expressions in one pass.
|
||||
let assert_operand_expression_is_lower = |operand_id: ExpressionId| {
|
||||
assert!(
|
||||
operand_id < id,
|
||||
"Operand {operand_id:?} should be less than {id:?} in {expression:?}",
|
||||
)
|
||||
};
|
||||
|
||||
// If an operand refers to a counter or expression that is always
|
||||
// zero, then that operand can be replaced with `CovTerm::Zero`.
|
||||
let maybe_set_operand_to_zero = |operand: &mut CovTerm| {
|
||||
if let CovTerm::Expression(id) = *operand {
|
||||
assert_operand_expression_is_lower(id);
|
||||
}
|
||||
|
||||
if is_zero_term(&counters_seen, &zero_expressions, *operand) {
|
||||
*operand = CovTerm::Zero;
|
||||
}
|
||||
};
|
||||
maybe_set_operand_to_zero(&mut lhs);
|
||||
maybe_set_operand_to_zero(&mut rhs);
|
||||
|
||||
// Coverage counter values cannot be negative, so if an expression
|
||||
// involves subtraction from zero, assume that its RHS must also be zero.
|
||||
// (Do this after simplifications that could set the LHS to zero.)
|
||||
if lhs == CovTerm::Zero && op == Op::Subtract {
|
||||
rhs = CovTerm::Zero;
|
||||
}
|
||||
|
||||
// After the above simplifications, if both operands are zero, then
|
||||
// we know that this expression is always zero too.
|
||||
if lhs == CovTerm::Zero && rhs == CovTerm::Zero {
|
||||
zero_expressions.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
zero_expressions
|
||||
}
|
||||
|
||||
/// Returns `true` if the given term is known to have a value of zero, taking
|
||||
/// into account knowledge of which counters are unused and which expressions
|
||||
/// are always zero.
|
||||
fn is_zero_term(
|
||||
counters_seen: &DenseBitSet<CounterId>,
|
||||
zero_expressions: &DenseBitSet<ExpressionId>,
|
||||
term: CovTerm,
|
||||
) -> bool {
|
||||
match term {
|
||||
CovTerm::Zero => true,
|
||||
CovTerm::Counter(id) => !counters_seen.contains(id),
|
||||
CovTerm::Expression(id) => zero_expressions.contains(id),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,8 +137,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
|
||||
|
||||
// These coverage statements should not exist prior to coverage instrumentation.
|
||||
StatementKind::Coverage(
|
||||
CoverageKind::CounterIncrement { .. }
|
||||
| CoverageKind::ExpressionUsed { .. }
|
||||
CoverageKind::VirtualCounter { .. }
|
||||
| CoverageKind::CondBitmapUpdate { .. }
|
||||
| CoverageKind::TestVectorBitmapUpdate { .. },
|
||||
) => bug!(
|
||||
|
||||
@@ -5,7 +5,6 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
field-offset = "0.3.5"
|
||||
measureme = "11"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use field_offset::offset_of;
|
||||
use rustc_data_structures::stable_hasher::HashStable;
|
||||
use rustc_data_structures::sync::AtomicU64;
|
||||
use rustc_middle::arena::Arena;
|
||||
@@ -89,7 +88,13 @@ fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key>
|
||||
where
|
||||
QueryCtxt<'tcx>: 'a,
|
||||
{
|
||||
self.dynamic.query_state.apply(&qcx.tcx.query_system.states)
|
||||
// Safety:
|
||||
// This is just manually doing the subfield referencing through pointer math.
|
||||
unsafe {
|
||||
&*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>)
|
||||
.byte_add(self.dynamic.query_state)
|
||||
.cast::<QueryState<Self::Key>>()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -97,7 +102,13 @@ fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
self.dynamic.query_cache.apply(&qcx.tcx.query_system.caches)
|
||||
// Safety:
|
||||
// This is just manually doing the subfield referencing through pointer math.
|
||||
unsafe {
|
||||
&*(&qcx.tcx.query_system.caches as *const QueryCaches<'tcx>)
|
||||
.byte_add(self.dynamic.query_cache)
|
||||
.cast::<Self::Cache>()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
||||
@@ -605,8 +605,8 @@ pub(crate) fn dynamic_query<'tcx>()
|
||||
eval_always: is_eval_always!([$($modifiers)*]),
|
||||
dep_kind: dep_graph::dep_kinds::$name,
|
||||
handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
|
||||
query_state: offset_of!(QueryStates<'tcx> => $name),
|
||||
query_cache: offset_of!(QueryCaches<'tcx> => $name),
|
||||
query_state: std::mem::offset_of!(QueryStates<'tcx>, $name),
|
||||
query_cache: std::mem::offset_of!(QueryCaches<'tcx>, $name),
|
||||
cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key),
|
||||
execute_query: |tcx, key| erase(tcx.$name(key)),
|
||||
compute: |tcx, key| {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#[cfg(not(test))]
|
||||
use core::ptr::{self, NonNull};
|
||||
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
// These are the magic symbols to call the global allocator. rustc generates
|
||||
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
|
||||
// (the code expanding that attribute macro generates those functions), or to call
|
||||
@@ -355,7 +355,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
||||
// # Allocation error handler
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
// This is the magic symbol to call the global alloc error handler. rustc generates
|
||||
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
|
||||
// default implementations below (`__rdl_oom`) otherwise.
|
||||
@@ -426,7 +426,7 @@ pub mod __alloc_error_handler {
|
||||
// `#[alloc_error_handler]`.
|
||||
#[rustc_std_internal_symbol]
|
||||
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
|
||||
// Its value depends on the -Zoom={panic,abort} compiler option.
|
||||
static __rust_alloc_error_handler_should_panic: u8;
|
||||
|
||||
@@ -74,7 +74,7 @@ pub(super) fn nexts<Cmp: Fn(&I::Item, &I::Item) -> Ordering>(
|
||||
b_next = self.b.next();
|
||||
}
|
||||
}
|
||||
if let (Some(ref a1), Some(ref b1)) = (&a_next, &b_next) {
|
||||
if let (Some(a1), Some(b1)) = (&a_next, &b_next) {
|
||||
match cmp(a1, b1) {
|
||||
Ordering::Less => self.peeked = b_next.take().map(Peeked::B),
|
||||
Ordering::Greater => self.peeked = a_next.take().map(Peeked::A),
|
||||
|
||||
@@ -397,7 +397,7 @@ pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
|
||||
// information about the size of the allocation is correct on Rust's
|
||||
// side.
|
||||
unsafe {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
/// Provided by libc or compiler_builtins.
|
||||
fn strlen(s: *const c_char) -> usize;
|
||||
}
|
||||
|
||||
@@ -1462,18 +1462,18 @@ pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
|
||||
/// Provides a raw pointer to the data.
|
||||
///
|
||||
/// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
|
||||
/// for as long there are strong counts in the `Rc`.
|
||||
/// for as long as there are strong counts in the `Rc`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let x = Rc::new("hello".to_owned());
|
||||
/// let x = Rc::new(0);
|
||||
/// let y = Rc::clone(&x);
|
||||
/// let x_ptr = Rc::as_ptr(&x);
|
||||
/// assert_eq!(x_ptr, Rc::as_ptr(&y));
|
||||
/// assert_eq!(unsafe { &*x_ptr }, "hello");
|
||||
/// assert_eq!(unsafe { *x_ptr }, 0);
|
||||
/// ```
|
||||
#[stable(feature = "weak_into_raw", since = "1.45.0")]
|
||||
#[rustc_never_returns_null_ptr]
|
||||
|
||||
@@ -731,7 +731,7 @@ fn as_ref(&self) -> &CStr {
|
||||
|
||||
len
|
||||
} else {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
/// Provided by libc or compiler_builtins.
|
||||
fn strlen(s: *const c_char) -> usize;
|
||||
}
|
||||
|
||||
@@ -90,4 +90,4 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
cfg(not(target_feature = "crt-static"))
|
||||
)]
|
||||
#[link(name = "/defaultlib:libcmt", modifiers = "+verbatim", cfg(target_feature = "crt-static"))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
@@ -4855,7 +4855,7 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 {
|
||||
#[cfg(miri)]
|
||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||
pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize) {
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
/// Miri-provided extern function to promise that a given pointer is properly aligned for
|
||||
/// "symbolic" alignment checks. Will fail if the pointer is not actually aligned or `align` is
|
||||
/// not a power of two. Has no effect when alignment checks are concrete (which is the default).
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_once_with", since = "1.43.0")]
|
||||
pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
|
||||
OnceWith { gen: Some(gen) }
|
||||
pub fn once_with<A, F: FnOnce() -> A>(make: F) -> OnceWith<F> {
|
||||
OnceWith { make: Some(make) }
|
||||
}
|
||||
|
||||
/// An iterator that yields a single element of type `A` by
|
||||
@@ -70,13 +70,13 @@ pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
|
||||
#[derive(Clone)]
|
||||
#[stable(feature = "iter_once_with", since = "1.43.0")]
|
||||
pub struct OnceWith<F> {
|
||||
gen: Option<F>,
|
||||
make: Option<F>,
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_once_with_debug", since = "1.68.0")]
|
||||
impl<F> fmt::Debug for OnceWith<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.gen.is_some() {
|
||||
if self.make.is_some() {
|
||||
f.write_str("OnceWith(Some(_))")
|
||||
} else {
|
||||
f.write_str("OnceWith(None)")
|
||||
@@ -90,13 +90,13 @@ impl<A, F: FnOnce() -> A> Iterator for OnceWith<F> {
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
let f = self.gen.take()?;
|
||||
let f = self.make.take()?;
|
||||
Some(f())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.gen.iter().size_hint()
|
||||
self.make.iter().size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ fn next_back(&mut self) -> Option<A> {
|
||||
#[stable(feature = "iter_once_with", since = "1.43.0")]
|
||||
impl<A, F: FnOnce() -> A> ExactSizeIterator for OnceWith<F> {
|
||||
fn len(&self) -> usize {
|
||||
self.gen.iter().len()
|
||||
self.make.iter().len()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
|
||||
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
// that gets resolved to the `#[panic_handler]` function.
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
#[lang = "panic_impl"]
|
||||
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||
}
|
||||
@@ -100,7 +100,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
|
||||
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
// that gets resolved to the `#[panic_handler]` function.
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
#[lang = "panic_impl"]
|
||||
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ pub struct DynMetadata<Dyn: ?Sized> {
|
||||
_phantom: crate::marker::PhantomData<Dyn>,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
/// Opaque type for accessing vtables.
|
||||
///
|
||||
/// Private implementation detail of `DynMetadata::size_of` etc.
|
||||
|
||||
@@ -648,7 +648,7 @@ struct Beta {
|
||||
z: dyn Trait,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
type Extern;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ fn ldexp_f32(a: f32, b: i32) -> f32 {
|
||||
}
|
||||
|
||||
fn ldexp_f64(a: f64, b: i32) -> f64 {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn ldexp(x: f64, n: i32) -> f64;
|
||||
}
|
||||
// SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly
|
||||
|
||||
@@ -97,7 +97,7 @@ fn test_is_null() {
|
||||
let nmi: *mut dyn ToString = null_mut::<isize>();
|
||||
assert!(nmi.is_null());
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
type Extern;
|
||||
}
|
||||
let ec: *const Extern = null::<Extern>();
|
||||
@@ -308,7 +308,7 @@ fn test_const_nonnull_new() {
|
||||
pub fn test_variadic_fnptr() {
|
||||
use core::ffi;
|
||||
use core::hash::{Hash, SipHasher};
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
// This needs to use the correct function signature even though it isn't called as some
|
||||
// codegen backends make it UB to declare a function with multiple conflicting signatures
|
||||
// (like LLVM) while others straight up return an error (like Cranelift).
|
||||
@@ -506,7 +506,7 @@ fn offset_from() {
|
||||
fn ptr_metadata() {
|
||||
struct Unit;
|
||||
struct Pair<A, B: ?Sized>(A, B);
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
type Extern;
|
||||
}
|
||||
let () = metadata(&());
|
||||
|
||||
@@ -54,7 +54,7 @@ unsafe fn abort() -> ! {
|
||||
))] {
|
||||
unsafe fn abort() -> ! {
|
||||
// call std::sys::abort_internal
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn __rust_abort() -> !;
|
||||
}
|
||||
__rust_abort();
|
||||
@@ -87,7 +87,7 @@ unsafe fn abort() -> ! {
|
||||
}
|
||||
} else if #[cfg(target_os = "teeos")] {
|
||||
mod teeos {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn TEE_Panic(code: u32) -> !;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ pub(crate) unsafe fn zkvm_set_abort_message(payload: &mut dyn PanicPayload) {
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn sys_panic(msg_ptr: *const u8, len: usize) -> !;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ struct TypeInfo {
|
||||
}
|
||||
unsafe impl Sync for TypeInfo {}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
// The leading `\x01` byte here is actually a magical signal to LLVM to
|
||||
// *not* apply any other mangling like prefixing with a `_` character.
|
||||
//
|
||||
@@ -119,7 +119,7 @@ extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
|
||||
fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;
|
||||
fn __cxa_end_catch();
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
use core::any::Any;
|
||||
|
||||
pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __rust_abort() -> !;
|
||||
}
|
||||
__rust_abort();
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __rust_abort() -> !;
|
||||
}
|
||||
__rust_abort();
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
/// Handler in std called when a panic object is dropped outside of
|
||||
/// `catch_unwind`.
|
||||
fn __rust_drop_panic() -> !;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// Must be pointer-sized.
|
||||
type Payload = Box<Box<dyn Any + Send>>;
|
||||
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
/// Miri-provided extern function to begin unwinding.
|
||||
fn miri_start_unwind(payload: *mut u8) -> !;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ mod imp {
|
||||
#[derive(Copy, Clone)]
|
||||
pub(super) struct ptr_t(u32);
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
static __ImageBase: u8;
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ struct _TypeDescriptor {
|
||||
copyFunction: ptr_t::null(),
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
// The leading `\x01` byte here is actually a magical signal to LLVM to
|
||||
// *not* apply any other mangling like prefixing with a `_` character.
|
||||
//
|
||||
@@ -343,7 +343,7 @@ pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
|
||||
ptr_t::new(exception_copy as *mut u8).raw(),
|
||||
);
|
||||
|
||||
extern "system-unwind" {
|
||||
unsafe extern "system-unwind" {
|
||||
fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||
#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))]
|
||||
pub mod eh_frames {
|
||||
#[no_mangle]
|
||||
#[link_section = ".eh_frame"]
|
||||
#[unsafe(link_section = ".eh_frame")]
|
||||
// Marks beginning of the stack frame unwind info section
|
||||
pub static __EH_FRAME_BEGIN__: [u8; 0] = [];
|
||||
|
||||
@@ -76,7 +76,7 @@ impl ::Copy for $t {}
|
||||
}
|
||||
|
||||
// Unwind info registration/deregistration routines.
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8);
|
||||
fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8);
|
||||
}
|
||||
@@ -101,10 +101,10 @@ pub mod mingw_init {
|
||||
// end of the list. Since constructors are run in reverse order, this ensures that our
|
||||
// callbacks are the first and last ones executed.
|
||||
|
||||
#[link_section = ".ctors.65535"] // .ctors.* : C initialization callbacks
|
||||
#[unsafe(link_section = ".ctors.65535")] // .ctors.* : C initialization callbacks
|
||||
pub static P_INIT: unsafe extern "C" fn() = super::init;
|
||||
|
||||
#[link_section = ".dtors.65535"] // .dtors.* : C termination callbacks
|
||||
#[unsafe(link_section = ".dtors.65535")] // .dtors.* : C termination callbacks
|
||||
pub static P_UNINIT: unsafe extern "C" fn() = super::uninit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,6 @@ pub mod eh_frames {
|
||||
// Terminate the frame unwind info section with a 0 as a sentinel;
|
||||
// this would be the 'length' field in a real FDE.
|
||||
#[no_mangle]
|
||||
#[link_section = ".eh_frame"]
|
||||
#[unsafe(link_section = ".eh_frame")]
|
||||
pub static __EH_FRAME_END__: u32 = 0;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ pub fn take_alloc_error_hook() -> fn(Layout) {
|
||||
}
|
||||
|
||||
fn default_alloc_error_hook(layout: Layout) {
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
|
||||
// Its value depends on the -Zoom={panic,abort} compiler option.
|
||||
static __rust_alloc_error_handler_should_panic: u8;
|
||||
|
||||
@@ -54,11 +54,11 @@
|
||||
// One day this may look a little less ad-hoc with the compiler helping out to
|
||||
// hook up these functions, but it is not this day!
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static);
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
/// `PanicPayload` lazily performs allocation only when needed (this avoids
|
||||
/// allocations when using the "abort" panic runtime).
|
||||
fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32;
|
||||
|
||||
@@ -616,9 +616,9 @@ pub fn capacity(&self) -> Option<usize> {
|
||||
#[unstable(feature = "mpmc_channel", issue = "126840")]
|
||||
pub fn same_channel(&self, other: &Sender<T>) -> bool {
|
||||
match (&self.flavor, &other.flavor) {
|
||||
(SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b,
|
||||
(SenderFlavor::List(ref a), SenderFlavor::List(ref b)) => a == b,
|
||||
(SenderFlavor::Zero(ref a), SenderFlavor::Zero(ref b)) => a == b,
|
||||
(SenderFlavor::Array(a), SenderFlavor::Array(b)) => a == b,
|
||||
(SenderFlavor::List(a), SenderFlavor::List(b)) => a == b,
|
||||
(SenderFlavor::Zero(a), SenderFlavor::Zero(b)) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new();
|
||||
|
||||
#[cfg(test)]
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
#[link_name = "_ZN16__rust_internals3std3sys4xous5alloc8DLMALLOCE"]
|
||||
static mut DLMALLOC: dlmalloc::Dlmalloc;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// These symbols are all defined by `libm`,
|
||||
// or by `compiler-builtins` on unsupported platforms.
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn acos(n: f64) -> f64;
|
||||
pub fn asin(n: f64) -> f64;
|
||||
pub fn atan(n: f64) -> f64;
|
||||
|
||||
@@ -78,7 +78,7 @@ pub unsafe fn cleanup() {}
|
||||
argv: *const *const c_char,
|
||||
env: *const *const c_char,
|
||||
) -> ! {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn main(argc: isize, argv: *const *const c_char) -> i32;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ pub struct T_CTSK {
|
||||
pub stk: *mut u8,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[link_name = "__asp3_acre_tsk"]
|
||||
pub fn acre_tsk(pk_ctsk: *const T_CTSK) -> ER_ID;
|
||||
#[link_name = "__asp3_get_tid"]
|
||||
|
||||
@@ -12,7 +12,7 @@ pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
|
||||
(image_base() + offset) as *mut T
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
static ENCLAVE_SIZE: usize;
|
||||
static HEAP_BASE: u64;
|
||||
static HEAP_SIZE: usize;
|
||||
|
||||
@@ -73,7 +73,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
|
||||
|
||||
EntryReturn(0, 0)
|
||||
} else {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn main(argc: isize, argv: *const *const u8) -> isize;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use crate::io::{self, Write};
|
||||
use crate::{cmp, mem};
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn take_debug_panic_buf_ptr() -> *mut u8;
|
||||
static DEBUG: u8;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ struct Rela<T> {
|
||||
}
|
||||
|
||||
pub fn relocate_elf_rela() {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
static RELA: u64;
|
||||
static RELACOUNT: usize;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// is a one-to-one correspondence of the ID to the address of the TCS.
|
||||
#[unstable(feature = "sgx_platform", issue = "56975")]
|
||||
pub fn current() -> Tcs {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn get_tcs_addr() -> *mut u8;
|
||||
}
|
||||
let addr = unsafe { get_tcs_addr() };
|
||||
|
||||
@@ -22,7 +22,7 @@ macro_rules! dup {
|
||||
#[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_DESTRUCTORE"]
|
||||
static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0)));
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn get_tls_ptr() -> *const u8;
|
||||
fn set_tls_ptr(tls: *const u8);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#[repr(C)]
|
||||
struct UsercallReturn(u64, u64);
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn usercall(nr: NonZero<u64>, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64)
|
||||
-> UsercallReturn;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub struct dirent {
|
||||
|
||||
pub type S_DIR = c_int;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn SOLID_FS_Open(fd: *mut c_int, path: *const c_char, mode: c_int) -> c_int;
|
||||
pub fn SOLID_FS_Close(fd: c_int) -> c_int;
|
||||
pub fn SOLID_FS_Read(fd: c_int, buf: *mut u8, size: usize, result: *mut usize) -> c_int;
|
||||
|
||||
@@ -33,27 +33,27 @@ pub struct SOLID_RTC_TIME {
|
||||
pub tm_wday: c_int,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int;
|
||||
}
|
||||
|
||||
// `solid_log.h`
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn SOLID_LOG_write(s: *const u8, l: usize);
|
||||
}
|
||||
|
||||
// `solid_mem.h`
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8));
|
||||
}
|
||||
|
||||
// `solid_rng.h`
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int;
|
||||
}
|
||||
|
||||
// `rwlock.h`
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn rwl_loc_rdl(id: ID) -> ER;
|
||||
pub fn rwl_loc_wrl(id: ID) -> ER;
|
||||
pub fn rwl_ploc_rdl(id: ID) -> ER;
|
||||
|
||||
@@ -158,7 +158,7 @@ pub struct fd_set {
|
||||
pub fds: [c_int; SOLID_NET_FD_SETSIZE],
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[link_name = "SOLID_NET_StrError"]
|
||||
pub fn strerror(errnum: c_int) -> *const c_char;
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
/// Returns a vector of (variable, value) byte-vector pairs for all the
|
||||
/// environment variables of the current process.
|
||||
pub fn env() -> Env {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
static mut environ: *const *const c_char;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ pub struct Thread {
|
||||
unsafe impl Send for Thread {}
|
||||
unsafe impl Sync for Thread {}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn TEE_Wait(timeout: u32) -> u32;
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
/// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
#[used]
|
||||
#[link_section = ".init_array.00099"]
|
||||
#[unsafe(link_section = ".init_array.00099")]
|
||||
static ARGV_INIT_ARRAY: extern "C" fn(
|
||||
crate::os::raw::c_int,
|
||||
*const *const u8,
|
||||
@@ -204,7 +204,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
|
||||
}
|
||||
|
||||
pub fn argc_argv() -> (isize, *const *const c_char) {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
// These functions are in crt_externs.h.
|
||||
fn _NSGetArgc() -> *mut c_int;
|
||||
fn _NSGetArgv() -> *mut *mut *mut c_char;
|
||||
|
||||
@@ -219,7 +219,7 @@ pub fn futex_wake_all(futex: &AtomicU32) {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "emscripten")]
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
|
||||
fn emscripten_futex_wait(
|
||||
addr: *const AtomicU32,
|
||||
@@ -267,7 +267,7 @@ pub mod zircon {
|
||||
pub const ZX_ERR_BAD_STATE: zx_status_t = -20;
|
||||
pub const ZX_ERR_TIMED_OUT: zx_status_t = -21;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn zx_clock_get_monotonic() -> zx_time_t;
|
||||
pub fn zx_futex_wait(
|
||||
value_ptr: *const zx_futex_t,
|
||||
|
||||
@@ -373,24 +373,24 @@ pub fn abort_internal() -> ! {
|
||||
cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "dl", cfg(not(target_feature = "crt-static")))]
|
||||
#[link(name = "log", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(target_os = "freebsd")] {
|
||||
#[link(name = "execinfo")]
|
||||
#[link(name = "pthread")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(target_os = "netbsd")] {
|
||||
#[link(name = "pthread")]
|
||||
#[link(name = "rt")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] {
|
||||
#[link(name = "pthread")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(target_os = "solaris")] {
|
||||
#[link(name = "socket")]
|
||||
#[link(name = "posix4")]
|
||||
#[link(name = "pthread")]
|
||||
#[link(name = "resolv")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(target_os = "illumos")] {
|
||||
#[link(name = "socket")]
|
||||
#[link(name = "posix4")]
|
||||
@@ -399,24 +399,24 @@ pub fn abort_internal() -> ! {
|
||||
#[link(name = "nsl")]
|
||||
// Use libumem for the (malloc-compatible) allocator
|
||||
#[link(name = "umem")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(target_vendor = "apple")] {
|
||||
// Link to `libSystem.dylib`.
|
||||
//
|
||||
// Don't get confused by the presence of `System.framework`,
|
||||
// it is a deprecated wrapper over the dynamic library.
|
||||
#[link(name = "System")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(target_os = "fuchsia")] {
|
||||
#[link(name = "zircon")]
|
||||
#[link(name = "fdio")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(all(target_os = "linux", target_env = "uclibc"))] {
|
||||
#[link(name = "dl")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(target_os = "vita")] {
|
||||
#[link(name = "pthread", kind = "static", modifiers = "-bundle")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
|
||||
#[cfg_attr(
|
||||
any(
|
||||
@@ -82,7 +82,7 @@ pub fn errno() -> i32 {
|
||||
|
||||
#[cfg(target_os = "rtems")]
|
||||
pub fn errno() -> i32 {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[thread_local]
|
||||
static _tls_errno: c_int;
|
||||
}
|
||||
@@ -92,7 +92,7 @@ pub fn errno() -> i32 {
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
pub fn errno() -> i32 {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[thread_local]
|
||||
static errno: c_int;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ pub fn errno() -> i32 {
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[allow(dead_code)]
|
||||
pub fn set_errno(e: i32) {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[thread_local]
|
||||
static mut errno: c_int;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ pub fn set_errno(e: i32) {
|
||||
|
||||
/// Gets a detailed string description for the given error number.
|
||||
pub fn error_string(errno: i32) -> String {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[cfg_attr(
|
||||
all(
|
||||
any(target_os = "linux", target_os = "hurd", target_env = "newlib"),
|
||||
@@ -610,7 +610,7 @@ pub unsafe fn environ() -> *mut *const *const c_char {
|
||||
// Use the `environ` static which is part of POSIX.
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub unsafe fn environ() -> *mut *const *const c_char {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
static mut environ: *const *const c_char;
|
||||
}
|
||||
&raw mut environ
|
||||
@@ -847,7 +847,7 @@ pub fn getppid() -> u32 {
|
||||
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
pub fn glibc_version() -> Option<(usize, usize)> {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn gnu_get_libc_version() -> *const libc::c_char;
|
||||
}
|
||||
let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) };
|
||||
|
||||
@@ -75,7 +75,7 @@ pub struct zx_info_process_t {
|
||||
pub reserved1: u32,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn zx_job_default() -> zx_handle_t;
|
||||
|
||||
pub fn zx_task_kill(handle: zx_handle_t) -> zx_status_t;
|
||||
@@ -115,7 +115,7 @@ pub struct fdio_spawn_action_t {
|
||||
pub reserved1: u64,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn fdio_spawn_etc(
|
||||
job: zx_handle_t,
|
||||
flags: u32,
|
||||
|
||||
@@ -23,7 +23,7 @@ mod zircon {
|
||||
type zx_status_t = i32;
|
||||
pub const ZX_PROP_NAME: u32 = 3;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn zx_object_set_property(
|
||||
handle: zx_handle_t,
|
||||
property: u32,
|
||||
@@ -230,7 +230,7 @@ pub fn set_name(name: &CStr) {
|
||||
#[cfg(target_os = "vxworks")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
// FIXME(libc): adding real STATUS, ERROR type eventually.
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn taskNameSet(task_id: libc::TASK_ID, task_name: *mut libc::c_char) -> libc::c_int;
|
||||
}
|
||||
|
||||
@@ -506,7 +506,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
} else if #[cfg(target_os = "vxworks")] {
|
||||
// Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF
|
||||
// expectations than the actual cores availability.
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn vxCpuEnabledGet() -> libc::cpuset_t;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
use crate::ptr;
|
||||
use crate::time::Duration;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn ___lwp_park60(
|
||||
clock_id: clockid_t,
|
||||
flags: c_int,
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
pub(crate) macro weak {
|
||||
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
|
||||
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[linkage = "extern_weak"]
|
||||
static $name: Option<unsafe extern "C" fn($($t),*) -> $ret>;
|
||||
}
|
||||
|
||||
@@ -787,7 +787,7 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn __wasilibc_find_relpath(
|
||||
path: *const libc::c_char,
|
||||
abs_prefix: *mut *const libc::c_char,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
mod libc {
|
||||
pub use libc::*;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
|
||||
pub fn chdir(dir: *const c_char) -> c_int;
|
||||
pub fn __wasilibc_get_environ() -> *mut *mut c_char;
|
||||
@@ -46,7 +46,7 @@ pub fn env_write_lock() -> impl Drop {
|
||||
}
|
||||
|
||||
pub fn errno() -> i32 {
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[thread_local]
|
||||
static errno: libc::c_int;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ pub struct pthread_attr_t {
|
||||
|
||||
pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn pthread_create(
|
||||
native: *mut pthread_t,
|
||||
attr: *const pthread_attr_t,
|
||||
|
||||
@@ -115,7 +115,7 @@ pub struct MOUNT_POINT_REPARSE_BUFFER {
|
||||
link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")
|
||||
)]
|
||||
#[cfg_attr(not(target_arch = "x86"), link(name = "bcryptprimitives", kind = "raw-dylib"))]
|
||||
extern "system" {
|
||||
unsafe extern "system" {
|
||||
pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ pub fn GetTempPath2W(bufferlength: u32, buffer: PWSTR) -> u32 {
|
||||
not(target_arch = "x86"),
|
||||
link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")
|
||||
)]
|
||||
extern "system" {
|
||||
unsafe extern "system" {
|
||||
pub fn WaitOnAddress(
|
||||
address: *const c_void,
|
||||
compareaddress: *const c_void,
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
// See https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170
|
||||
#[cfg(target_vendor = "win7")]
|
||||
#[used]
|
||||
#[link_section = ".CRT$XCT"]
|
||||
#[unsafe(link_section = ".CRT$XCT")]
|
||||
static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;
|
||||
|
||||
/// Preload some imported functions.
|
||||
|
||||
@@ -44,7 +44,7 @@ pub struct FileType {
|
||||
}
|
||||
|
||||
pub struct ReadDir {
|
||||
handle: FindNextFileHandle,
|
||||
handle: Option<FindNextFileHandle>,
|
||||
root: Arc<PathBuf>,
|
||||
first: Option<c::WIN32_FIND_DATAW>,
|
||||
}
|
||||
@@ -113,13 +113,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
impl Iterator for ReadDir {
|
||||
type Item = io::Result<DirEntry>;
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
if self.handle.0 == c::INVALID_HANDLE_VALUE {
|
||||
let Some(handle) = self.handle.as_ref() else {
|
||||
// This iterator was initialized with an `INVALID_HANDLE_VALUE` as its handle.
|
||||
// Simply return `None` because this is only the case when `FindFirstFileExW` in
|
||||
// the construction of this iterator returns `ERROR_FILE_NOT_FOUND` which means
|
||||
// no matchhing files can be found.
|
||||
return None;
|
||||
}
|
||||
};
|
||||
if let Some(first) = self.first.take() {
|
||||
if let Some(e) = DirEntry::new(&self.root, &first) {
|
||||
return Some(Ok(e));
|
||||
@@ -128,7 +128,7 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
unsafe {
|
||||
let mut wfd = mem::zeroed();
|
||||
loop {
|
||||
if c::FindNextFileW(self.handle.0, &mut wfd) == 0 {
|
||||
if c::FindNextFileW(handle.0, &mut wfd) == 0 {
|
||||
match api::get_last_error() {
|
||||
WinError::NO_MORE_FILES => return None,
|
||||
WinError { code } => {
|
||||
@@ -1194,7 +1194,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
|
||||
|
||||
if find_handle != c::INVALID_HANDLE_VALUE {
|
||||
Ok(ReadDir {
|
||||
handle: FindNextFileHandle(find_handle),
|
||||
handle: Some(FindNextFileHandle(find_handle)),
|
||||
root: Arc::new(root),
|
||||
first: Some(wfd),
|
||||
})
|
||||
@@ -1212,11 +1212,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
|
||||
// See issue #120040: https://github.com/rust-lang/rust/issues/120040.
|
||||
let last_error = api::get_last_error();
|
||||
if last_error == WinError::FILE_NOT_FOUND {
|
||||
return Ok(ReadDir {
|
||||
handle: FindNextFileHandle(find_handle),
|
||||
root: Arc::new(root),
|
||||
first: None,
|
||||
});
|
||||
return Ok(ReadDir { handle: None, root: Arc::new(root), first: None });
|
||||
}
|
||||
|
||||
// Just return the error constructed from the raw OS error if the above is not the case.
|
||||
|
||||
@@ -33,7 +33,7 @@ fn test_thread_handle() {
|
||||
assert!(p.is_ok());
|
||||
let mut p = p.unwrap();
|
||||
|
||||
extern "system" {
|
||||
unsafe extern "system" {
|
||||
fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
|
||||
}
|
||||
unsafe {
|
||||
|
||||
@@ -37,7 +37,7 @@ fn find(&self, _pc: usize) -> Option<unwind::FrameInfo> {
|
||||
#[cfg(not(test))]
|
||||
mod c_compat {
|
||||
use crate::os::xous::ffi::exit;
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn main() -> u32;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ pub mod fileno {
|
||||
pub const JOURNAL: u32 = 3;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
// Wrappers around syscalls provided by risc0-zkvm-platform:
|
||||
pub fn sys_halt();
|
||||
pub fn sys_output(output_id: u32, output_value: u32);
|
||||
|
||||
@@ -194,7 +194,7 @@ unsafe fn continue_unwind(
|
||||
}
|
||||
}
|
||||
// defined in libgcc
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn __gnu_unwind_frame(
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
target_os = "vita", // See https://github.com/vitasdk/newlib/blob/b89e5bc183b516945f9ee07eef483ecb916e45ff/newlib/libc/include/stdlib.h#L74
|
||||
))]
|
||||
#[cfg_attr(target_os = "haiku", link(name = "bsd"))]
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn arc4random_buf(buf: *mut core::ffi::c_void, nbytes: libc::size_t);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::ffi::c_void;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn esp_fill_random(buf: *mut c_void, len: usize);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! <https://fuchsia.dev/reference/syscalls/cprng_draw>.
|
||||
|
||||
#[link(name = "zircon")]
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn zx_cprng_draw(buffer: *mut u8, len: usize);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
const DISPATCH_TIME_FOREVER: dispatch_time_t = !0;
|
||||
|
||||
// Contained in libSystem.dylib, which is linked by default.
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t;
|
||||
fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t;
|
||||
fn dispatch_semaphore_wait(dsema: dispatch_semaphore_t, timeout: dispatch_time_t) -> isize;
|
||||
|
||||
@@ -27,7 +27,7 @@ pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct c_int(#[allow(dead_code)] pub core::ffi::c_int);
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
#[linkage = "extern_weak"]
|
||||
static __dso_handle: *mut u8;
|
||||
#[linkage = "extern_weak"]
|
||||
|
||||
@@ -10,7 +10,7 @@ pub fn enable() {
|
||||
#[thread_local]
|
||||
static REGISTERED: Cell<bool> = Cell::new(false);
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ pub fn enable() {
|
||||
unsafe { ptr::from_ref(&CALLBACK).read_volatile() };
|
||||
}
|
||||
|
||||
#[link_section = ".CRT$XLB"]
|
||||
#[unsafe(link_section = ".CRT$XLB")]
|
||||
#[cfg_attr(miri, used)] // Miri only considers explicitly `#[used]` statics for `lookup_link_section`
|
||||
pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = tls_callback;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ mod libc {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pthread_key_t = ffi::c_uint;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn pthread_key_create(
|
||||
key: *mut pthread_key_t,
|
||||
destructor: unsafe extern "C" fn(*mut ffi::c_void),
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
#[cfg(test)]
|
||||
extern "Rust" {
|
||||
unsafe extern "Rust" {
|
||||
#[link_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key13TLS_KEY_INDEXE"]
|
||||
static TLS_KEY_INDEX: AtomicUsize;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
fn switch_stdout_to(file: OwnedFd) -> OwnedFd {
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn dup(old: i32) -> i32;
|
||||
fn dup2(old: i32, new: i32) -> i32;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ fn switch_stdout_to(file: OwnedFd) -> OwnedFd {
|
||||
fn switch_stdout_to(file: OwnedHandle) -> OwnedHandle {
|
||||
use std::os::windows::prelude::*;
|
||||
|
||||
extern "system" {
|
||||
unsafe extern "system" {
|
||||
fn GetStdHandle(nStdHandle: u32) -> *mut u8;
|
||||
fn SetStdHandle(nStdHandle: u32, handle: *mut u8) -> i32;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
/// Attempting to delete a running binary should return an error on Windows.
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // `remove_file` does not work in Miri on Windows
|
||||
fn win_delete_self() {
|
||||
let path = std::env::current_exe().unwrap();
|
||||
assert!(std::fs::remove_file(path).is_err());
|
||||
|
||||
@@ -314,9 +314,10 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
|
||||
let mut st = ConsoleTestState::new(opts)?;
|
||||
|
||||
// Prevent the usage of `Instant` in some cases:
|
||||
// - It's currently not supported for wasm targets.
|
||||
// - It's currently not supported for wasm targets without Emscripten nor WASI.
|
||||
// - It's currently not supported for zkvm targets.
|
||||
let is_instant_unsupported =
|
||||
(cfg!(target_family = "wasm") && !cfg!(target_os = "wasi")) || cfg!(target_os = "zkvm");
|
||||
(cfg!(target_family = "wasm") && cfg!(target_os = "unknown")) || cfg!(target_os = "zkvm");
|
||||
|
||||
let start_time = (!is_instant_unsupported).then(Instant::now);
|
||||
run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?;
|
||||
|
||||
@@ -184,12 +184,16 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) {
|
||||
// If we're being run in SpawnedSecondary mode, run the test here. run_test
|
||||
// will then exit the process.
|
||||
if let Ok(name) = env::var(SECONDARY_TEST_INVOKER_VAR) {
|
||||
env::remove_var(SECONDARY_TEST_INVOKER_VAR);
|
||||
unsafe {
|
||||
env::remove_var(SECONDARY_TEST_INVOKER_VAR);
|
||||
}
|
||||
|
||||
// Convert benchmarks to tests if we're not benchmarking.
|
||||
let mut tests = tests.iter().map(make_owned_test).collect::<Vec<_>>();
|
||||
if env::var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR).is_ok() {
|
||||
env::remove_var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR);
|
||||
unsafe {
|
||||
env::remove_var(SECONDARY_TEST_BENCH_BENCHMARKS_VAR);
|
||||
}
|
||||
} else {
|
||||
tests = convert_benchmarks_to_tests(tests);
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ struct CONSOLE_SCREEN_BUFFER_INFO {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
unsafe extern "system" {
|
||||
fn SetConsoleTextAttribute(handle: HANDLE, attr: WORD) -> BOOL;
|
||||
fn GetStdHandle(which: DWORD) -> HANDLE;
|
||||
fn GetConsoleScreenBufferInfo(handle: HANDLE, info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL;
|
||||
|
||||
+23
-23
@@ -56,15 +56,15 @@
|
||||
compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
|
||||
} else if #[cfg(feature = "llvm-libunwind")] {
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else if #[cfg(feature = "system-llvm-libunwind")] {
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else {
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,11 +76,11 @@
|
||||
compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
|
||||
} else if #[cfg(feature = "llvm-libunwind")] {
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else {
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,14 +91,14 @@
|
||||
} else {
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
}
|
||||
}
|
||||
// Android's unwinding library depends on dl_iterate_phdr in `libdl`.
|
||||
#[cfg(target_os = "android")]
|
||||
#[link(name = "dl", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "dl", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
// When building with crt-static, we get `gcc_eh` from the `libc` crate, since
|
||||
// glibc needs it, and needs it listed later on the linker command line. We
|
||||
@@ -110,7 +110,7 @@
|
||||
not(feature = "system-llvm-libunwind")
|
||||
))]
|
||||
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(all(
|
||||
target_os = "linux",
|
||||
@@ -119,67 +119,67 @@
|
||||
feature = "system-llvm-libunwind"
|
||||
))]
|
||||
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "gcc_eh", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(all(target_os = "openbsd", target_arch = "sparc64"))]
|
||||
#[link(name = "gcc")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(all(target_os = "openbsd", not(target_arch = "sparc64")))]
|
||||
#[link(name = "c++abi")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
#[link(name = "gcc_pic")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(target_os = "aix")]
|
||||
#[link(name = "unwind")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(target_os = "nto")]
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_env = "nto70")] {
|
||||
#[link(name = "gcc")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
} else {
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "hurd")]
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))]
|
||||
#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
|
||||
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
@@ -108,10 +108,10 @@ pub enum _Unwind_Context {}
|
||||
),
|
||||
link(name = "unwind", kind = "static", modifiers = "-bundle")
|
||||
)]
|
||||
extern "C-unwind" {
|
||||
unsafe extern "C-unwind" {
|
||||
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
|
||||
}
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
|
||||
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
|
||||
pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||
@@ -140,7 +140,7 @@ pub enum _Unwind_Action {
|
||||
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
|
||||
link(name = "unwind", kind = "static", modifiers = "-bundle")
|
||||
)]
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
|
||||
pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
|
||||
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
|
||||
@@ -198,7 +198,7 @@ enum _Unwind_VRS_DataRepresentation {
|
||||
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
|
||||
link(name = "unwind", kind = "static", modifiers = "-bundle")
|
||||
)]
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
|
||||
regclass: _Unwind_VRS_RegClass,
|
||||
regno: _Unwind_Word,
|
||||
@@ -261,7 +261,7 @@ pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
|
||||
if #[cfg(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm"))] {
|
||||
// 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj and
|
||||
// does not provide _Unwind_Backtrace()
|
||||
extern "C-unwind" {
|
||||
unsafe extern "C-unwind" {
|
||||
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
@@ -271,14 +271,14 @@ pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
|
||||
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
|
||||
link(name = "unwind", kind = "static", modifiers = "-bundle")
|
||||
)]
|
||||
extern "C-unwind" {
|
||||
unsafe extern "C-unwind" {
|
||||
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||
}
|
||||
#[cfg_attr(
|
||||
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")),
|
||||
link(name = "unwind", kind = "static", modifiers = "-bundle")
|
||||
)]
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
|
||||
trace_argument: *mut c_void)
|
||||
-> _Unwind_Reason_Code;
|
||||
@@ -302,7 +302,7 @@ pub enum DISPATCHER_CONTEXT {}
|
||||
context: *mut _Unwind_Context)
|
||||
-> _Unwind_Reason_Code;
|
||||
|
||||
extern "C" {
|
||||
unsafe extern "C" {
|
||||
pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
|
||||
establisherFrame: LPVOID,
|
||||
contextRecord: *mut CONTEXT,
|
||||
|
||||
@@ -39,4 +39,4 @@
|
||||
#[link(name = "userenv")]
|
||||
#[link(name = "ws2_32")]
|
||||
#[link(name = "dbghelp")] // required for backtrace-rs symbolization
|
||||
extern "C" {}
|
||||
unsafe extern "C" {}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user