Auto merge of #126679 - fmease:rollup-njrv2py, r=fmease
Rollup of 6 pull requests Successful merges: - #125447 (Allow constraining opaque types during subtyping in the trait system) - #125766 (MCDC Coverage: instrument last boolean RHS operands from condition coverage) - #125880 (Remove `src/tools/rust-demangler`) - #126154 (StorageLive: refresh storage (instead of UB) when local is already live) - #126572 (override user defined channel when using precompiled rustc) - #126662 (Unconditionally warn on usage of `wasm32-wasi`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
3186d17d56
35 changed files with 675 additions and 588 deletions
|
@ -3479,14 +3479,6 @@ dependencies = [
|
|||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-demangler"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustbook"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -23,7 +23,6 @@ members = [
|
|||
"src/tools/remote-test-client",
|
||||
"src/tools/remote-test-server",
|
||||
"src/tools/rust-installer",
|
||||
"src/tools/rust-demangler",
|
||||
"src/tools/rustdoc",
|
||||
"src/tools/rls",
|
||||
"src/tools/rustfmt",
|
||||
|
|
|
@ -73,8 +73,6 @@ const_eval_division_by_zero =
|
|||
dividing by zero
|
||||
const_eval_division_overflow =
|
||||
overflow in signed division (dividing MIN by -1)
|
||||
const_eval_double_storage_live =
|
||||
StorageLive on a local that was already live
|
||||
|
||||
const_eval_dyn_call_not_a_method =
|
||||
`dyn` call trying to call something that is not a method
|
||||
|
|
|
@ -1100,11 +1100,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
Operand::Immediate(Immediate::Uninit)
|
||||
});
|
||||
|
||||
// StorageLive expects the local to be dead, and marks it live.
|
||||
// If the local is already live, deallocate its old memory.
|
||||
let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
|
||||
if !matches!(old, LocalValue::Dead) {
|
||||
throw_ub_custom!(fluent::const_eval_double_storage_live);
|
||||
}
|
||||
self.deallocate_local(old)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1118,7 +1116,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
|
||||
trace!("{:?} is now dead", local);
|
||||
|
||||
// It is entirely okay for this local to be already dead (at least that's how we currently generate MIR)
|
||||
// If the local is already dead, this is a NOP.
|
||||
let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
|
||||
self.deallocate_local(old)?;
|
||||
Ok(())
|
||||
|
|
|
@ -878,9 +878,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
|
||||
if a_is_expected {
|
||||
Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b))
|
||||
Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b))
|
||||
} else {
|
||||
Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a))
|
||||
Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -361,16 +361,19 @@ pub enum StatementKind<'tcx> {
|
|||
/// At any point during the execution of a function, each local is either allocated or
|
||||
/// unallocated. Except as noted below, all locals except function parameters are initially
|
||||
/// unallocated. `StorageLive` statements cause memory to be allocated for the local while
|
||||
/// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only
|
||||
/// reading/writing from it) while it is unallocated is UB.
|
||||
/// `StorageDead` statements cause the memory to be freed. In other words,
|
||||
/// `StorageLive`/`StorageDead` act like the heap operations `allocate`/`deallocate`, but for
|
||||
/// stack-allocated local variables. Using a local in any way (not only reading/writing from it)
|
||||
/// while it is unallocated is UB.
|
||||
///
|
||||
/// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body.
|
||||
/// These locals are implicitly allocated for the full duration of the function. There is a
|
||||
/// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for
|
||||
/// computing these locals.
|
||||
///
|
||||
/// If the local is already allocated, calling `StorageLive` again is UB. However, for an
|
||||
/// unallocated local an additional `StorageDead` all is simply a nop.
|
||||
/// If the local is already allocated, calling `StorageLive` again will implicitly free the
|
||||
/// local and then allocate fresh uninitilized memory. If a local is already deallocated,
|
||||
/// calling `StorageDead` again is a NOP.
|
||||
StorageLive(Local),
|
||||
|
||||
/// See `StorageLive` above.
|
||||
|
|
|
@ -118,17 +118,35 @@ impl BranchInfoBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_two_way_branch<'tcx>(
|
||||
fn register_two_way_branch<'tcx>(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cfg: &mut CFG<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
true_block: BasicBlock,
|
||||
false_block: BasicBlock,
|
||||
) {
|
||||
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
|
||||
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
|
||||
// Separate path for handling branches when MC/DC is enabled.
|
||||
if let Some(mcdc_info) = self.mcdc_info.as_mut() {
|
||||
let inject_block_marker =
|
||||
|source_info, block| self.markers.inject_block_marker(cfg, source_info, block);
|
||||
mcdc_info.visit_evaluated_condition(
|
||||
tcx,
|
||||
source_info,
|
||||
true_block,
|
||||
false_block,
|
||||
inject_block_marker,
|
||||
);
|
||||
} else {
|
||||
let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block);
|
||||
let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block);
|
||||
|
||||
self.branch_spans.push(BranchSpan { span: source_info.span, true_marker, false_marker });
|
||||
self.branch_spans.push(BranchSpan {
|
||||
span: source_info.span,
|
||||
true_marker,
|
||||
false_marker,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> {
|
||||
|
@ -205,7 +223,14 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block),
|
||||
);
|
||||
|
||||
branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
|
||||
// Separate path for handling branches when MC/DC is enabled.
|
||||
branch_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
true_block,
|
||||
false_block,
|
||||
);
|
||||
|
||||
let join_block = self.cfg.start_new_block();
|
||||
self.cfg.goto(true_block, source_info, join_block);
|
||||
|
@ -236,22 +261,13 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
|
||||
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
|
||||
|
||||
// Separate path for handling branches when MC/DC is enabled.
|
||||
if let Some(mcdc_info) = branch_info.mcdc_info.as_mut() {
|
||||
let inject_block_marker = |source_info, block| {
|
||||
branch_info.markers.inject_block_marker(&mut self.cfg, source_info, block)
|
||||
};
|
||||
mcdc_info.visit_evaluated_condition(
|
||||
self.tcx,
|
||||
source_info,
|
||||
then_block,
|
||||
else_block,
|
||||
inject_block_marker,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
|
||||
branch_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
then_block,
|
||||
else_block,
|
||||
);
|
||||
}
|
||||
|
||||
/// If branch coverage is enabled, inject marker statements into `true_block`
|
||||
|
@ -270,6 +286,12 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
// FIXME(#124144) This may need special handling when MC/DC is enabled.
|
||||
|
||||
let source_info = SourceInfo { span: pattern.span, scope: self.source_scope };
|
||||
branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
|
||||
branch_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
true_block,
|
||||
false_block,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,6 +150,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
ExprKind::LogicalOp { op, lhs, rhs } => {
|
||||
let condition_scope = this.local_scope();
|
||||
let source_info = this.source_info(expr.span);
|
||||
|
||||
this.visit_coverage_branch_operation(op, expr.span);
|
||||
|
||||
// We first evaluate the left-hand side of the predicate ...
|
||||
let (then_block, else_block) =
|
||||
this.in_if_then_scope(condition_scope, expr.span, |this| {
|
||||
|
|
|
@ -1311,6 +1311,20 @@ pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &
|
|||
for warning in warnings.warning_messages() {
|
||||
early_dcx.early_warn(warning)
|
||||
}
|
||||
|
||||
// The `wasm32-wasi` target is being renamed to `wasm32-wasip1` as
|
||||
// part of rust-lang/compiler-team#607 and
|
||||
// rust-lang/compiler-team#695. Warn unconditionally on usage to
|
||||
// raise awareness of the renaming. This code will be deleted in
|
||||
// October 2024.
|
||||
if opts.target_triple.triple() == "wasm32-wasi" {
|
||||
early_dcx.early_warn(
|
||||
"the `wasm32-wasi` target is being renamed to \
|
||||
`wasm32-wasip1` and the `wasm32-wasi` target will be \
|
||||
removed from nightly in October 2024 and removed from \
|
||||
stable Rust in January 2025",
|
||||
)
|
||||
}
|
||||
if !matches!(target.pointer_width, 16 | 32 | 64) {
|
||||
early_dcx.early_fatal(format!(
|
||||
"target specification was invalid: unrecognized target-pointer-width {}",
|
||||
|
|
|
@ -321,8 +321,7 @@
|
|||
#
|
||||
# If `extended = false`, the only one of these built by default is rustdoc.
|
||||
#
|
||||
# If `extended = true`, they're all included, with the exception of
|
||||
# rust-demangler which additionally requires `profiler = true` to be set.
|
||||
# If `extended = true`, they are all included.
|
||||
#
|
||||
# If any enabled tool fails to build, the installation fails.
|
||||
#tools = [
|
||||
|
@ -334,7 +333,6 @@
|
|||
# "rust-analyzer-proc-macro-srv",
|
||||
# "analysis",
|
||||
# "src",
|
||||
# "rust-demangler", # if profiler = true
|
||||
#]
|
||||
|
||||
# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
|
||||
|
|
|
@ -322,7 +322,6 @@ lint_any!(
|
|||
RemoteTestServer, "src/tools/remote-test-server", "remote-test-server";
|
||||
Rls, "src/tools/rls", "rls";
|
||||
RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer";
|
||||
RustDemangler, "src/tools/rust-demangler", "rust-demangler";
|
||||
Rustdoc, "src/tools/rustdoc", "clippy";
|
||||
Rustfmt, "src/tools/rustfmt", "rustfmt";
|
||||
RustInstaller, "src/tools/rust-installer", "rust-installer";
|
||||
|
|
|
@ -1459,62 +1459,6 @@ impl Step for Rustfmt {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct RustDemangler {
|
||||
pub compiler: Compiler,
|
||||
pub target: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for RustDemangler {
|
||||
type Output = Option<GeneratedTarball>;
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
// While other tools use `should_build_extended_tool` to decide whether to be run by
|
||||
// default or not, `rust-demangler` must be build when *either* it's enabled as a tool like
|
||||
// the other ones or if `profiler = true`. Because we don't know the target at this stage
|
||||
// we run the step by default when only `extended = true`, and decide whether to actually
|
||||
// run it or not later.
|
||||
let default = run.builder.config.extended;
|
||||
run.alias("rust-demangler").default_condition(default)
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(RustDemangler {
|
||||
compiler: run.builder.compiler_for(
|
||||
run.builder.top_stage,
|
||||
run.builder.config.build,
|
||||
run.target,
|
||||
),
|
||||
target: run.target,
|
||||
});
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
|
||||
let compiler = self.compiler;
|
||||
let target = self.target;
|
||||
|
||||
// Only build this extended tool if explicitly included in `tools`, or if `profiler = true`
|
||||
let condition = should_build_extended_tool(builder, "rust-demangler")
|
||||
|| builder.config.profiler_enabled(target);
|
||||
if builder.config.extended && !condition {
|
||||
return None;
|
||||
}
|
||||
|
||||
let rust_demangler =
|
||||
builder.ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() });
|
||||
|
||||
// Prepare the image directory
|
||||
let mut tarball = Tarball::new(builder, "rust-demangler", &target.triple);
|
||||
tarball.set_overlay(OverlayKind::RustDemangler);
|
||||
tarball.is_preview(true);
|
||||
tarball.add_file(rust_demangler, "bin", 0o755);
|
||||
tarball.add_legal_and_readme_to("share/doc/rust-demangler");
|
||||
Some(tarball.generate())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Extended {
|
||||
stage: u32,
|
||||
|
@ -1572,7 +1516,6 @@ impl Step for Extended {
|
|||
|
||||
add_component!("rust-docs" => Docs { host: target });
|
||||
add_component!("rust-json-docs" => JsonDocs { host: target });
|
||||
add_component!("rust-demangler"=> RustDemangler { compiler, target });
|
||||
add_component!("cargo" => Cargo { compiler, target });
|
||||
add_component!("rustfmt" => Rustfmt { compiler, target });
|
||||
add_component!("rls" => Rls { compiler, target });
|
||||
|
@ -1636,7 +1579,7 @@ impl Step for Extended {
|
|||
|
||||
let xform = |p: &Path| {
|
||||
let mut contents = t!(fs::read_to_string(p));
|
||||
for tool in &["rust-demangler", "miri", "rust-docs"] {
|
||||
for tool in &["miri", "rust-docs"] {
|
||||
if !built_tools.contains(tool) {
|
||||
contents = filter(&contents, tool);
|
||||
}
|
||||
|
@ -1677,7 +1620,7 @@ impl Step for Extended {
|
|||
prepare("rust-analysis");
|
||||
prepare("clippy");
|
||||
prepare("rust-analyzer");
|
||||
for tool in &["rust-docs", "rust-demangler", "miri", "rustc-codegen-cranelift"] {
|
||||
for tool in &["rust-docs", "miri", "rustc-codegen-cranelift"] {
|
||||
if built_tools.contains(tool) {
|
||||
prepare(tool);
|
||||
}
|
||||
|
@ -1717,8 +1660,6 @@ impl Step for Extended {
|
|||
"rust-analyzer-preview".to_string()
|
||||
} else if name == "clippy" {
|
||||
"clippy-preview".to_string()
|
||||
} else if name == "rust-demangler" {
|
||||
"rust-demangler-preview".to_string()
|
||||
} else if name == "miri" {
|
||||
"miri-preview".to_string()
|
||||
} else if name == "rustc-codegen-cranelift" {
|
||||
|
@ -1738,7 +1679,7 @@ impl Step for Extended {
|
|||
prepare("cargo");
|
||||
prepare("rust-analysis");
|
||||
prepare("rust-std");
|
||||
for tool in &["clippy", "rust-analyzer", "rust-docs", "rust-demangler", "miri"] {
|
||||
for tool in &["clippy", "rust-analyzer", "rust-docs", "miri"] {
|
||||
if built_tools.contains(tool) {
|
||||
prepare(tool);
|
||||
}
|
||||
|
@ -1862,25 +1803,6 @@ impl Step for Extended {
|
|||
.arg(etc.join("msi/remove-duplicates.xsl")),
|
||||
);
|
||||
}
|
||||
if built_tools.contains("rust-demangler") {
|
||||
builder.run(
|
||||
Command::new(&heat)
|
||||
.current_dir(&exe)
|
||||
.arg("dir")
|
||||
.arg("rust-demangler")
|
||||
.args(heat_flags)
|
||||
.arg("-cg")
|
||||
.arg("RustDemanglerGroup")
|
||||
.arg("-dr")
|
||||
.arg("RustDemangler")
|
||||
.arg("-var")
|
||||
.arg("var.RustDemanglerDir")
|
||||
.arg("-out")
|
||||
.arg(exe.join("RustDemanglerGroup.wxs"))
|
||||
.arg("-t")
|
||||
.arg(etc.join("msi/remove-duplicates.xsl")),
|
||||
);
|
||||
}
|
||||
if built_tools.contains("miri") {
|
||||
builder.run(
|
||||
Command::new(&heat)
|
||||
|
@ -1958,9 +1880,6 @@ impl Step for Extended {
|
|||
if built_tools.contains("rust-docs") {
|
||||
cmd.arg("-dDocsDir=rust-docs");
|
||||
}
|
||||
if built_tools.contains("rust-demangler") {
|
||||
cmd.arg("-dRustDemanglerDir=rust-demangler");
|
||||
}
|
||||
if built_tools.contains("rust-analyzer") {
|
||||
cmd.arg("-dRustAnalyzerDir=rust-analyzer");
|
||||
}
|
||||
|
@ -1987,9 +1906,6 @@ impl Step for Extended {
|
|||
if built_tools.contains("miri") {
|
||||
candle("MiriGroup.wxs".as_ref());
|
||||
}
|
||||
if built_tools.contains("rust-demangler") {
|
||||
candle("RustDemanglerGroup.wxs".as_ref());
|
||||
}
|
||||
if built_tools.contains("rust-analyzer") {
|
||||
candle("RustAnalyzerGroup.wxs".as_ref());
|
||||
}
|
||||
|
@ -2031,9 +1947,6 @@ impl Step for Extended {
|
|||
if built_tools.contains("rust-analyzer") {
|
||||
cmd.arg("RustAnalyzerGroup.wixobj");
|
||||
}
|
||||
if built_tools.contains("rust-demangler") {
|
||||
cmd.arg("RustDemanglerGroup.wixobj");
|
||||
}
|
||||
if built_tools.contains("rust-docs") {
|
||||
cmd.arg("DocsGroup.wixobj");
|
||||
}
|
||||
|
|
|
@ -265,22 +265,6 @@ install!((self, builder, _config),
|
|||
);
|
||||
}
|
||||
};
|
||||
RustDemangler, alias = "rust-demangler", Self::should_build(_config), only_hosts: true, {
|
||||
// NOTE: Even though `should_build` may return true for `extended` default tools,
|
||||
// dist::RustDemangler may still return None, unless the target-dependent `profiler` config
|
||||
// is also true, or the `tools` array explicitly includes "rust-demangler".
|
||||
if let Some(tarball) = builder.ensure(dist::RustDemangler {
|
||||
compiler: self.compiler,
|
||||
target: self.target
|
||||
}) {
|
||||
install_sh(builder, "rust-demangler", self.compiler.stage, Some(self.target), &tarball);
|
||||
} else {
|
||||
builder.info(
|
||||
&format!("skipping Install RustDemangler stage{} ({})",
|
||||
self.compiler.stage, self.target),
|
||||
);
|
||||
}
|
||||
};
|
||||
Rustc, path = "compiler/rustc", true, only_hosts: true, {
|
||||
let tarball = builder.ensure(dist::Rustc {
|
||||
compiler: builder.compiler(builder.top_stage, self.target),
|
||||
|
|
|
@ -432,65 +432,6 @@ impl Step for Rustfmt {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct RustDemangler {
|
||||
stage: u32,
|
||||
host: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for RustDemangler {
|
||||
type Output = ();
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/tools/rust-demangler")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(RustDemangler { stage: run.builder.top_stage, host: run.target });
|
||||
}
|
||||
|
||||
/// Runs `cargo test` for rust-demangler.
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let stage = self.stage;
|
||||
let host = self.host;
|
||||
let compiler = builder.compiler(stage, host);
|
||||
|
||||
let rust_demangler = builder.ensure(tool::RustDemangler {
|
||||
compiler,
|
||||
target: self.host,
|
||||
extra_features: Vec::new(),
|
||||
});
|
||||
let mut cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolRustc,
|
||||
host,
|
||||
"test",
|
||||
"src/tools/rust-demangler",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
|
||||
let dir = testdir(builder, compiler.host);
|
||||
t!(fs::create_dir_all(dir));
|
||||
|
||||
cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
|
||||
cargo.add_rustc_lib_path(builder);
|
||||
|
||||
run_cargo_test(
|
||||
cargo,
|
||||
&[],
|
||||
&[],
|
||||
"rust-demangler",
|
||||
"rust-demangler",
|
||||
compiler,
|
||||
host,
|
||||
builder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Miri {
|
||||
target: TargetSelection,
|
||||
|
|
|
@ -964,7 +964,6 @@ tool_extended!((self, builder),
|
|||
// But `builder.cargo` doesn't know how to handle ToolBootstrap in stages other than 0,
|
||||
// and this is close enough for now.
|
||||
Rls, "src/tools/rls", "rls", stable=true, tool_std=true;
|
||||
RustDemangler, "src/tools/rust-demangler", "rust-demangler", stable=false, tool_std=true;
|
||||
Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, add_bins_to_sysroot = ["rustfmt", "cargo-fmt"];
|
||||
);
|
||||
|
||||
|
|
|
@ -736,7 +736,6 @@ impl<'a> Builder<'a> {
|
|||
tool::Rls,
|
||||
tool::RustAnalyzer,
|
||||
tool::RustAnalyzerProcMacroSrv,
|
||||
tool::RustDemangler,
|
||||
tool::Rustdoc,
|
||||
tool::Clippy,
|
||||
tool::CargoClippy,
|
||||
|
@ -774,7 +773,6 @@ impl<'a> Builder<'a> {
|
|||
clippy::RemoteTestServer,
|
||||
clippy::Rls,
|
||||
clippy::RustAnalyzer,
|
||||
clippy::RustDemangler,
|
||||
clippy::Rustdoc,
|
||||
clippy::Rustfmt,
|
||||
clippy::RustInstaller,
|
||||
|
@ -842,7 +840,6 @@ impl<'a> Builder<'a> {
|
|||
test::Miri,
|
||||
test::CargoMiri,
|
||||
test::Clippy,
|
||||
test::RustDemangler,
|
||||
test::CompiletestTest,
|
||||
test::CrateRunMakeSupport,
|
||||
test::RustdocJSStd,
|
||||
|
@ -903,7 +900,6 @@ impl<'a> Builder<'a> {
|
|||
dist::Rls,
|
||||
dist::RustAnalyzer,
|
||||
dist::Rustfmt,
|
||||
dist::RustDemangler,
|
||||
dist::Clippy,
|
||||
dist::Miri,
|
||||
dist::LlvmTools,
|
||||
|
@ -930,7 +926,6 @@ impl<'a> Builder<'a> {
|
|||
install::Cargo,
|
||||
install::RustAnalyzer,
|
||||
install::Rustfmt,
|
||||
install::RustDemangler,
|
||||
install::Clippy,
|
||||
install::Miri,
|
||||
install::LlvmTools,
|
||||
|
@ -1036,23 +1031,12 @@ impl<'a> Builder<'a> {
|
|||
}
|
||||
|
||||
pub fn doc_rust_lang_org_channel(&self) -> String {
|
||||
// When using precompiled compiler from CI, we need to use CI rustc's channel and
|
||||
// ignore `rust.channel` from the configuration. Otherwise most of the rustdoc tests
|
||||
// will fail due to incompatible `DOC_RUST_LANG_ORG_CHANNEL`.
|
||||
let channel = if let Some(commit) = self.config.download_rustc_commit() {
|
||||
self.config
|
||||
.read_file_by_commit(&PathBuf::from("src/ci/channel"), commit)
|
||||
.trim()
|
||||
.to_owned()
|
||||
} else {
|
||||
match &*self.config.channel {
|
||||
"stable" => &self.version,
|
||||
"beta" => "beta",
|
||||
"nightly" | "dev" => "nightly",
|
||||
// custom build of rustdoc maybe? link to the latest stable docs just in case
|
||||
_ => "stable",
|
||||
}
|
||||
.to_owned()
|
||||
let channel = match &*self.config.channel {
|
||||
"stable" => &self.version,
|
||||
"beta" => "beta",
|
||||
"nightly" | "dev" => "nightly",
|
||||
// custom build of rustdoc maybe? link to the latest stable docs just in case
|
||||
_ => "stable",
|
||||
};
|
||||
|
||||
format!("https://doc.rust-lang.org/{channel}")
|
||||
|
|
|
@ -1718,7 +1718,23 @@ impl Config {
|
|||
config.omit_git_hash = omit_git_hash.unwrap_or(default);
|
||||
config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
|
||||
|
||||
if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel {
|
||||
// We need to override `rust.channel` if it's manually specified when using the CI rustc.
|
||||
// This is because if the compiler uses a different channel than the one specified in config.toml,
|
||||
// tests may fail due to using a different channel than the one used by the compiler during tests.
|
||||
if let Some(commit) = &config.download_rustc_commit {
|
||||
if is_user_configured_rust_channel {
|
||||
println!(
|
||||
"WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
|
||||
);
|
||||
|
||||
let channel = config
|
||||
.read_file_by_commit(&PathBuf::from("src/ci/channel"), commit)
|
||||
.trim()
|
||||
.to_owned();
|
||||
|
||||
config.channel = channel;
|
||||
}
|
||||
} else if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel {
|
||||
ci_channel.clone_into(&mut config.channel);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ pub(crate) enum OverlayKind {
|
|||
Clippy,
|
||||
Miri,
|
||||
Rustfmt,
|
||||
RustDemangler,
|
||||
Rls,
|
||||
RustAnalyzer,
|
||||
RustcCodegenCranelift,
|
||||
|
@ -58,9 +57,6 @@ impl OverlayKind {
|
|||
"src/tools/rustfmt/LICENSE-APACHE",
|
||||
"src/tools/rustfmt/LICENSE-MIT",
|
||||
],
|
||||
OverlayKind::RustDemangler => {
|
||||
&["src/tools/rust-demangler/README.md", "LICENSE-APACHE", "LICENSE-MIT"]
|
||||
}
|
||||
OverlayKind::Rls => &["src/tools/rls/README.md", "LICENSE-APACHE", "LICENSE-MIT"],
|
||||
OverlayKind::RustAnalyzer => &[
|
||||
"src/tools/rust-analyzer/README.md",
|
||||
|
@ -85,7 +81,6 @@ impl OverlayKind {
|
|||
match self {
|
||||
OverlayKind::Rust => builder.rust_version(),
|
||||
OverlayKind::Llvm => builder.rust_version(),
|
||||
OverlayKind::RustDemangler => builder.release_num("rust-demangler"),
|
||||
OverlayKind::Cargo => {
|
||||
builder.cargo_info.version(builder, &builder.release_num("cargo"))
|
||||
}
|
||||
|
|
|
@ -49,12 +49,6 @@ One option for a Rust demangler is [`rustfilt`], which can be installed with:
|
|||
cargo install rustfilt
|
||||
```
|
||||
|
||||
Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with:
|
||||
|
||||
```shell
|
||||
$ ./x.py build rust-demangler
|
||||
```
|
||||
|
||||
[`rustfilt`]: https://crates.io/crates/rustfilt
|
||||
|
||||
## Compiling with coverage enabled
|
||||
|
@ -164,7 +158,7 @@ $ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \
|
|||
|
||||
Some of the more notable options in this example include:
|
||||
|
||||
- `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool)
|
||||
- `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example)
|
||||
- `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map)
|
||||
- `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary)
|
||||
- `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`)
|
||||
|
|
14
src/tools/miri/tests/fail/storage-live-dead-var.rs
Normal file
14
src/tools/miri/tests/fail/storage-live-dead-var.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
#![feature(core_intrinsics, custom_mir)]
|
||||
use std::intrinsics::mir::*;
|
||||
|
||||
#[custom_mir(dialect = "runtime")]
|
||||
fn main() {
|
||||
mir! {
|
||||
let val: i32;
|
||||
{
|
||||
val = 42; //~ERROR: accessing a dead local variable
|
||||
StorageLive(val); // too late... (but needs to be here to make `val` not implicitly live)
|
||||
Return()
|
||||
}
|
||||
}
|
||||
}
|
15
src/tools/miri/tests/fail/storage-live-dead-var.stderr
Normal file
15
src/tools/miri/tests/fail/storage-live-dead-var.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error: Undefined Behavior: accessing a dead local variable
|
||||
--> $DIR/storage-live-dead-var.rs:LL:CC
|
||||
|
|
||||
LL | val = 42;
|
||||
| ^^^^^^^^ accessing a dead local variable
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/storage-live-dead-var.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
17
src/tools/miri/tests/fail/storage-live-resets-var.rs
Normal file
17
src/tools/miri/tests/fail/storage-live-resets-var.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#![feature(core_intrinsics, custom_mir)]
|
||||
use std::intrinsics::mir::*;
|
||||
|
||||
#[custom_mir(dialect = "runtime")]
|
||||
fn main() {
|
||||
mir! {
|
||||
let val: i32;
|
||||
let _val2: i32;
|
||||
{
|
||||
StorageLive(val);
|
||||
val = 42;
|
||||
StorageLive(val); // reset val to `uninit`
|
||||
_val2 = val; //~ERROR: uninitialized
|
||||
Return()
|
||||
}
|
||||
}
|
||||
}
|
15
src/tools/miri/tests/fail/storage-live-resets-var.stderr
Normal file
15
src/tools/miri/tests/fail/storage-live-resets-var.stderr
Normal file
|
@ -0,0 +1,15 @@
|
|||
error: Undefined Behavior: constructing invalid value: encountered uninitialized memory, but expected an integer
|
||||
--> $DIR/storage-live-resets-var.rs:LL:CC
|
||||
|
|
||||
LL | _val2 = val;
|
||||
| ^^^^^^^^^^^ constructing invalid value: encountered uninitialized memory, but expected an integer
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/storage-live-resets-var.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
[package]
|
||||
name = "rust-demangler"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
regex = "1.0"
|
||||
rustc-demangle = "0.1.17"
|
||||
|
||||
[lib]
|
||||
name = "rust_demangler"
|
||||
doctest = false
|
||||
|
||||
[[bin]]
|
||||
name = "rust-demangler"
|
||||
test = false
|
|
@ -1,36 +0,0 @@
|
|||
# rust-demangler
|
||||
|
||||
_Demangles rustc mangled names._
|
||||
|
||||
`rust-demangler` supports the requirements of the [`llvm-cov show -Xdemangler`
|
||||
option](https://llvm.org/docs/CommandGuide/llvm-cov.html#cmdoption-llvm-cov-show-xdemangler),
|
||||
to perform Rust-specific symbol demangling:
|
||||
|
||||
> _The demangler is expected to read a newline-separated list of symbols from
|
||||
> stdin and write a newline-separated list of the same length to stdout._
|
||||
|
||||
To use `rust-demangler` with `llvm-cov` for example:
|
||||
|
||||
```shell
|
||||
$ TARGET="${PWD}/build/x86_64-unknown-linux-gnu"
|
||||
$ "${TARGET}"/llvm/bin/llvm-cov show \
|
||||
--Xdemangler=path/to/rust-demangler \
|
||||
--instr-profile=main.profdata ./main --show-line-counts-or-regions
|
||||
```
|
||||
|
||||
`rust-demangler` is a Rust "extended tool", used in Rust compiler tests, and
|
||||
optionally included in Rust distributions that enable coverage profiling. Symbol
|
||||
demangling is implemented using the
|
||||
[rustc-demangle](https://crates.io/crates/rustc-demangle) crate.
|
||||
|
||||
_(Note, for Rust developers, the third-party tool
|
||||
[`rustfilt`](https://crates.io/crates/rustfilt) also supports `llvm-cov` symbol
|
||||
demangling. `rustfilt` is a more generalized tool that searches any body of
|
||||
text, using pattern matching, to find and demangle Rust symbols.)_
|
||||
|
||||
## License
|
||||
|
||||
Rust-demangler is distributed under the terms of both the MIT license and the
|
||||
Apache License (Version 2.0).
|
||||
|
||||
See [LICENSE-APACHE](/LICENSE-APACHE) and [LICENSE-MIT](/LICENSE-MIT) for details.
|
|
@ -1,21 +0,0 @@
|
|||
use regex::Regex;
|
||||
use rustc_demangle::demangle;
|
||||
use std::str::Lines;
|
||||
|
||||
const REPLACE_COLONS: &str = "::";
|
||||
|
||||
pub fn create_disambiguator_re() -> Regex {
|
||||
Regex::new(r"\[[a-f0-9]{5,16}\]::").unwrap()
|
||||
}
|
||||
|
||||
pub fn demangle_lines(lines: Lines<'_>, strip_crate_disambiguators: Option<Regex>) -> Vec<String> {
|
||||
let mut demangled_lines = Vec::new();
|
||||
for mangled in lines {
|
||||
let mut demangled = demangle(mangled).to_string();
|
||||
if let Some(re) = &strip_crate_disambiguators {
|
||||
demangled = re.replace_all(&demangled, REPLACE_COLONS).to_string();
|
||||
}
|
||||
demangled_lines.push(demangled);
|
||||
}
|
||||
demangled_lines
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
//! Demangles rustc mangled names.
|
||||
//!
|
||||
//! Note regarding crate disambiguators:
|
||||
//!
|
||||
//! Some demangled symbol paths can include "crate disambiguator" suffixes, represented as a large
|
||||
//! hexadecimal value enclosed in square braces, and appended to the name of the crate. a suffix to the
|
||||
//! original crate name. For example, the `core` crate, here, includes a disambiguator:
|
||||
//!
|
||||
//! ```rust
|
||||
//! <generics::Firework<f64> as core[a7a74cee373f048]::ops::drop::Drop>::drop
|
||||
//! ```
|
||||
//!
|
||||
//! These disambiguators are known to vary depending on environmental circumstances. As a result,
|
||||
//! tests that compare results including demangled names can fail across development environments,
|
||||
//! particularly with cross-platform testing. Also, the resulting crate paths are not syntactically
|
||||
//! valid, and don't match the original source symbol paths, which can impact development tools.
|
||||
//!
|
||||
//! For these reasons, by default, `rust-demangler` uses a heuristic to remove crate disambiguators
|
||||
//! from their original demangled representation before printing them to standard output. If crate
|
||||
//! disambiguators are required, add the `-d` (or `--disambiguators`) flag, and the disambiguators
|
||||
//! will not be removed.
|
||||
//!
|
||||
//! Also note that the disambiguators are stripped by a Regex pattern that is tolerant to some
|
||||
//! variation in the number of hexadecimal digits. The disambiguators come from a hash value, which
|
||||
//! typically generates a 16-digit hex representation on a 64-bit architecture; however, leading
|
||||
//! zeros are not included, which can shorten the hex digit length, and a different hash algorithm
|
||||
//! that might also be dependent on the architecture, might shorten the length even further. A
|
||||
//! minimum length of 5 digits is assumed, which should be more than sufficient to support hex
|
||||
//! representations that generate only 8-digits of precision with an extremely rare (but not
|
||||
//! impossible) result with up to 3 leading zeros.
|
||||
//!
|
||||
//! Using a minimum number of digits less than 5 risks the possibility of stripping demangled name
|
||||
//! components with a similar pattern. For example, some closures instantiated multiple times
|
||||
//! include their own disambiguators, demangled as non-hashed zero-based indexes in square brackets.
|
||||
//! These disambiguators seem to have more analytical value (for instance, in coverage analysis), so
|
||||
//! they are not removed.
|
||||
|
||||
use rust_demangler::*;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
// FIXME(richkadel): In Issue #77615 discussed updating the `rustc-demangle` library, to provide
|
||||
// an option to generate demangled names without including crate disambiguators. If that
|
||||
// happens, update this tool to use that option (if the `-d` flag is not set) instead stripping
|
||||
// them via the Regex heuristic. The update the doc comments and help.
|
||||
|
||||
// Strip hashed hexadecimal crate disambiguators. Leading zeros are not enforced, and can be
|
||||
// different across different platform/architecture types, so while 16 hex digits are common,
|
||||
// they can also be shorter.
|
||||
//
|
||||
// Also note that a demangled symbol path may include the `[<digits>]` pattern, with zero-based
|
||||
// indexes (such as for closures, and possibly for types defined in anonymous scopes). Preferably
|
||||
// these should not be stripped.
|
||||
//
|
||||
// The minimum length of 5 digits supports the possibility that some target architecture (maybe
|
||||
// a 32-bit or smaller architecture) could generate a hash value with a maximum of 8 digits,
|
||||
// and more than three leading zeros should be extremely unlikely. Conversely, it should be
|
||||
// sufficient to assume the zero-based indexes for closures and anonymous scopes will never
|
||||
// exceed the value 9999.
|
||||
let mut strip_crate_disambiguators = Some(create_disambiguator_re());
|
||||
|
||||
let mut args = std::env::args();
|
||||
let progname = args.next().unwrap();
|
||||
for arg in args {
|
||||
if arg == "--disambiguators" || arg == "-d" {
|
||||
strip_crate_disambiguators = None;
|
||||
} else {
|
||||
eprintln!();
|
||||
eprintln!("Usage: {} [-d|--disambiguators]", progname);
|
||||
eprintln!();
|
||||
eprintln!(
|
||||
"This tool converts a list of Rust mangled symbols (one per line) into a\n\
|
||||
corresponding list of demangled symbols."
|
||||
);
|
||||
eprintln!();
|
||||
eprintln!(
|
||||
"With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\
|
||||
include crate disambiguators (a hexadecimal hash value, typically up to 16 digits\n\
|
||||
long, enclosed in square brackets)."
|
||||
);
|
||||
eprintln!();
|
||||
eprintln!(
|
||||
"By default, crate disambiguators are removed, using a heuristics-based regular\n\
|
||||
expression. (See the `rust-demangler` doc comments for more information.)"
|
||||
);
|
||||
eprintln!();
|
||||
std::process::exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
let mut buffer = String::new();
|
||||
io::stdin().read_to_string(&mut buffer)?;
|
||||
let mut demangled_lines = demangle_lines(buffer.lines(), strip_crate_disambiguators);
|
||||
demangled_lines.push("".to_string()); // ensure a trailing newline
|
||||
io::stdout().write_all(demangled_lines.join("\n").as_bytes())?;
|
||||
Ok(())
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
use rust_demangler::*;
|
||||
|
||||
const MANGLED_INPUT: &str = r"
|
||||
_RNvC6_123foo3bar
|
||||
_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y
|
||||
_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_
|
||||
_RNCINkXs25_NgCsbmNqQUJIY6D_4core5sliceINyB9_4IterhENuNgNoBb_4iter8iterator8Iterator9rpositionNCNgNpB9_6memchr7memrchrs_0E0Bb_
|
||||
_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std
|
||||
INtC8arrayvec8ArrayVechKj7b_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_8UnsignedKhb_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKs98_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKanb_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb0_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb1_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc76_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKca_E
|
||||
_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc2202_E
|
||||
_RNvNvMCs4fqI2P2rA04_13const_genericINtB4_3FooKpE3foo3FOO
|
||||
_RC3foo.llvm.9D1C9369
|
||||
_RC3foo.llvm.9D1C9369@@16
|
||||
_RNvC9backtrace3foo.llvm.A5310EB9
|
||||
_RNvNtNtNtNtCs92dm3009vxr_4rand4rngs7adapter9reseeding4fork23FORK_HANDLER_REGISTERED.0.0
|
||||
";
|
||||
|
||||
const DEMANGLED_OUTPUT: &str = r"
|
||||
123foo[0]::bar
|
||||
utf8_idents[317d481089b8c8fe]::საჭმელად_გემრიელი_სადილი
|
||||
cc[4d6468d6c9fd4bb3]::spawn::{closure#0}::{closure#0}
|
||||
<core[846817f741e54dfd]::slice::Iter<u8> as core[846817f741e54dfd]::iter::iterator::Iterator>::rposition::<core[846817f741e54dfd]::slice::memchr::memrchr::{closure#1}>::{closure#0}
|
||||
alloc[f15a878b47eb696b]::alloc::box_free::<dyn alloc[f15a878b47eb696b]::boxed::FnBox<(), Output = ()>>
|
||||
INtC8arrayvec8ArrayVechKj7b_E
|
||||
<const_generic[317d481089b8c8fe]::Unsigned<11u8>>
|
||||
<const_generic[317d481089b8c8fe]::Signed<152i16>>
|
||||
<const_generic[317d481089b8c8fe]::Signed<-11i8>>
|
||||
<const_generic[317d481089b8c8fe]::Bool<false>>
|
||||
<const_generic[317d481089b8c8fe]::Bool<true>>
|
||||
<const_generic[317d481089b8c8fe]::Char<'v'>>
|
||||
<const_generic[317d481089b8c8fe]::Char<'\n'>>
|
||||
<const_generic[317d481089b8c8fe]::Char<'∂'>>
|
||||
<const_generic[317d481089b8c8fe]::Foo<_>>::foo::FOO
|
||||
foo[0]
|
||||
foo[0]
|
||||
backtrace[0]::foo
|
||||
rand[693ea8e72247470f]::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0
|
||||
";
|
||||
|
||||
const DEMANGLED_OUTPUT_NO_CRATE_DISAMBIGUATORS: &str = r"
|
||||
123foo[0]::bar
|
||||
utf8_idents::საჭმელად_გემრიელი_სადილი
|
||||
cc::spawn::{closure#0}::{closure#0}
|
||||
<core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0}
|
||||
alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>
|
||||
INtC8arrayvec8ArrayVechKj7b_E
|
||||
<const_generic::Unsigned<11u8>>
|
||||
<const_generic::Signed<152i16>>
|
||||
<const_generic::Signed<-11i8>>
|
||||
<const_generic::Bool<false>>
|
||||
<const_generic::Bool<true>>
|
||||
<const_generic::Char<'v'>>
|
||||
<const_generic::Char<'\n'>>
|
||||
<const_generic::Char<'∂'>>
|
||||
<const_generic::Foo<_>>::foo::FOO
|
||||
foo[0]
|
||||
foo[0]
|
||||
backtrace[0]::foo
|
||||
rand::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0
|
||||
";
|
||||
|
||||
#[test]
|
||||
fn test_demangle_lines() {
|
||||
let demangled_lines = demangle_lines(MANGLED_INPUT.lines(), None);
|
||||
for (expected, actual) in DEMANGLED_OUTPUT.lines().zip(demangled_lines) {
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_demangle_lines_no_crate_disambiguators() {
|
||||
let demangled_lines = demangle_lines(MANGLED_INPUT.lines(), Some(create_disambiguator_re()));
|
||||
for (expected, actual) in DEMANGLED_OUTPUT_NO_CRATE_DISAMBIGUATORS.lines().zip(demangled_lines)
|
||||
{
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
204
tests/coverage/mcdc_non_control_flow.cov-map
Normal file
204
tests/coverage/mcdc_non_control_flow.cov-map
Normal file
|
@ -0,0 +1,204 @@
|
|||
Function name: mcdc_non_control_flow::assign_3
|
||||
Raw bytes (89): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 22, 01, 00, 02, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 9
|
||||
- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add)
|
||||
- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4)
|
||||
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 4 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 5 operands: lhs = Expression(8, Sub), rhs = Counter(4)
|
||||
- expression 6 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(4)
|
||||
- expression 8 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 10
|
||||
- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 40)
|
||||
- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
|
||||
= (c1 + ((c2 + c3) + c4))
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(8, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Expression(8, Sub)) at (prev + 0, 18) to (start + 0, 19)
|
||||
= (c0 - c1)
|
||||
- MCDCBranch { true: Expression(7, Sub), false: Counter(4), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = ((c0 - c1) - c4)
|
||||
false = c4
|
||||
- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 24)
|
||||
= ((c0 - c1) - c4)
|
||||
- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
|
||||
true = c2
|
||||
false = c3
|
||||
- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
|
||||
= (c1 + ((c2 + c3) + c4))
|
||||
|
||||
Function name: mcdc_non_control_flow::assign_3_bis
|
||||
Raw bytes (85): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 1a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 16, 03, 00, 02, 00, 12, 00, 13, 13, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 7
|
||||
- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4)
|
||||
- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 4 operands: lhs = Expression(5, Sub), rhs = Expression(6, Sub)
|
||||
- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 6 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 10
|
||||
- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 44)
|
||||
- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
|
||||
= ((c2 + c3) + c4)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(5, Sub), condition_id: 3, true_next_id: 0, false_next_id: 2 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Expression(4, Add)) at (prev + 0, 23) to (start + 0, 24)
|
||||
= ((c1 - c2) + (c0 - c1))
|
||||
- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
|
||||
true = c3
|
||||
false = c4
|
||||
- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
|
||||
= ((c2 + c3) + c4)
|
||||
|
||||
Function name: mcdc_non_control_flow::assign_and
|
||||
Raw bytes (64): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 08, 01, 0c, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 4
|
||||
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(3, Sub)
|
||||
- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 8
|
||||
- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 33)
|
||||
- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
|
||||
= ((c2 + c3) + (c0 - c1))
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c2
|
||||
false = c3
|
||||
- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
|
||||
= ((c2 + c3) + (c0 - c1))
|
||||
|
||||
Function name: mcdc_non_control_flow::assign_or
|
||||
Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 4
|
||||
- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 8
|
||||
- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 32)
|
||||
- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
|
||||
= ((c1 + c2) + c3)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19)
|
||||
= (c0 - c1)
|
||||
- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c2
|
||||
false = c3
|
||||
- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
|
||||
= ((c1 + c2) + c3)
|
||||
|
||||
Function name: mcdc_non_control_flow::foo
|
||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 02, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 1
|
||||
- Code(Counter(0)) at (prev + 37, 1) to (start + 2, 2)
|
||||
|
||||
Function name: mcdc_non_control_flow::func_call
|
||||
Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 29, 01, 01, 0a, 28, 00, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 07, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 3
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Expression(2, Add), rhs = Expression(0, Sub)
|
||||
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
Number of file 0 mappings: 6
|
||||
- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 10)
|
||||
- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 9) to (start + 0, 10)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15)
|
||||
- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15)
|
||||
true = c2
|
||||
false = c3
|
||||
- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
|
||||
= ((c2 + c3) + (c0 - c1))
|
||||
|
||||
Function name: mcdc_non_control_flow::right_comb_tree
|
||||
Raw bytes (139): 0x[01, 01, 13, 07, 1a, 0b, 19, 0f, 15, 13, 11, 09, 0d, 01, 05, 01, 05, 05, 19, 05, 19, 4a, 15, 05, 19, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 0e, 01, 20, 01, 00, 41, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 4a, 19, 02, 03, 00, 00, 13, 00, 14, 4a, 00, 19, 00, 1a, 30, 46, 15, 03, 04, 00, 00, 19, 00, 1a, 46, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 09, 0d, 05, 00, 00, 00, 24, 00, 27, 03, 01, 05, 01, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 19
|
||||
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(6, Sub)
|
||||
- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(6)
|
||||
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
|
||||
- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4)
|
||||
- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 5 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 6 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 7 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 8 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 9 operands: lhs = Expression(18, Sub), rhs = Counter(5)
|
||||
- expression 10 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 11 operands: lhs = Expression(18, Sub), rhs = Counter(5)
|
||||
- expression 12 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 13 operands: lhs = Expression(17, Sub), rhs = Counter(4)
|
||||
- expression 14 operands: lhs = Expression(18, Sub), rhs = Counter(5)
|
||||
- expression 15 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(4)
|
||||
- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(5)
|
||||
- expression 18 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
Number of file 0 mappings: 14
|
||||
- Code(Counter(0)) at (prev + 32, 1) to (start + 0, 65)
|
||||
- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
|
||||
= (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 0, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 19) to (start + 0, 20)
|
||||
- MCDCBranch { true: Expression(18, Sub), false: Counter(6), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20)
|
||||
true = (c1 - c6)
|
||||
false = c6
|
||||
- Code(Expression(18, Sub)) at (prev + 0, 25) to (start + 0, 26)
|
||||
= (c1 - c6)
|
||||
- MCDCBranch { true: Expression(17, Sub), false: Counter(5), condition_id: 3, true_next_id: 4, false_next_id: 0 } at (prev + 0, 25) to (start + 0, 26)
|
||||
true = ((c1 - c6) - c5)
|
||||
false = c5
|
||||
- Code(Expression(17, Sub)) at (prev + 0, 31) to (start + 0, 32)
|
||||
= ((c1 - c6) - c5)
|
||||
- MCDCBranch { true: Expression(16, Sub), false: Counter(4), condition_id: 4, true_next_id: 5, false_next_id: 0 } at (prev + 0, 31) to (start + 0, 32)
|
||||
true = (((c1 - c6) - c5) - c4)
|
||||
false = c4
|
||||
- Code(Expression(16, Sub)) at (prev + 0, 36) to (start + 0, 39)
|
||||
= (((c1 - c6) - c5) - c4)
|
||||
- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39)
|
||||
true = c2
|
||||
false = c3
|
||||
- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
|
||||
= (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))
|
||||
|
202
tests/coverage/mcdc_non_control_flow.coverage
Normal file
202
tests/coverage/mcdc_non_control_flow.coverage
Normal file
|
@ -0,0 +1,202 @@
|
|||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ min-llvm-version: 18
|
||||
LL| |//@ compile-flags: -Zcoverage-options=mcdc
|
||||
LL| |//@ llvm-cov-flags: --show-mcdc
|
||||
LL| |
|
||||
LL| |// This test ensures that boolean expressions that are not inside control flow
|
||||
LL| |// decisions are correctly instrumented.
|
||||
LL| |
|
||||
LL| |use core::hint::black_box;
|
||||
LL| |
|
||||
LL| 3|fn assign_and(a: bool, b: bool) {
|
||||
LL| 3| let x = a && b;
|
||||
^2
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:19)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3| black_box(x);
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 3|fn assign_or(a: bool, b: bool) {
|
||||
LL| 3| let x = a || b;
|
||||
^1
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:19)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, F = F }
|
||||
| 2 { T, - = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,2)
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 50.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3| black_box(x);
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 4|fn assign_3(a: bool, b: bool, c: bool) {
|
||||
LL| 4| let x = a || b && c;
|
||||
^2 ^1
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:24)
|
||||
|
|
||||
| Number of Conditions: 3
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
| Condition C3 --> (LL:23)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3 Result
|
||||
| 1 { F, F, - = F }
|
||||
| 2 { T, -, - = T }
|
||||
| 3 { F, T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,2)
|
||||
| C2-Pair: covered: (1,3)
|
||||
| C3-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 66.67%
|
||||
|
|
||||
------------------
|
||||
LL| 4| black_box(x);
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 4|fn assign_3_bis(a: bool, b: bool, c: bool) {
|
||||
LL| 4| let x = a && b || c;
|
||||
^2 ^3
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:24)
|
||||
|
|
||||
| Number of Conditions: 3
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
| Condition C3 --> (LL:23)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3 Result
|
||||
| 1 { T, F, F = F }
|
||||
| 2 { F, -, T = T }
|
||||
| 3 { T, T, - = T }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: covered: (1,3)
|
||||
| C3-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 33.33%
|
||||
|
|
||||
------------------
|
||||
LL| 4| black_box(x);
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 3|fn right_comb_tree(a: bool, b: bool, c: bool, d: bool, e: bool) {
|
||||
LL| 3| let x = a && (b && (c && (d && (e))));
|
||||
^2 ^1 ^1 ^1
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:42)
|
||||
|
|
||||
| Number of Conditions: 5
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:19)
|
||||
| Condition C3 --> (LL:25)
|
||||
| Condition C4 --> (LL:31)
|
||||
| Condition C5 --> (LL:36)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3, C4, C5 Result
|
||||
| 1 { F, -, -, -, - = F }
|
||||
| 2 { T, F, -, -, - = F }
|
||||
| 3 { T, T, T, T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| C3-Pair: not covered
|
||||
| C4-Pair: not covered
|
||||
| C5-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 40.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3| black_box(x);
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 3|fn foo(a: bool) -> bool {
|
||||
LL| 3| black_box(a)
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 3|fn func_call(a: bool, b: bool) {
|
||||
LL| 3| foo(a && b);
|
||||
^2
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:9) to (LL:15)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:9)
|
||||
| Condition C2 --> (LL:14)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | assign_and(true, false);
|
||||
LL| | assign_and(true, true);
|
||||
LL| | assign_and(false, false);
|
||||
LL| |
|
||||
LL| | assign_or(true, false);
|
||||
LL| | assign_or(true, true);
|
||||
LL| | assign_or(false, false);
|
||||
LL| |
|
||||
LL| | assign_3(true, false, false);
|
||||
LL| | assign_3(true, true, false);
|
||||
LL| | assign_3(false, false, true);
|
||||
LL| | assign_3(false, true, true);
|
||||
LL| |
|
||||
LL| | assign_3_bis(true, false, false);
|
||||
LL| | assign_3_bis(true, true, false);
|
||||
LL| | assign_3_bis(false, false, true);
|
||||
LL| | assign_3_bis(false, true, true);
|
||||
LL| |
|
||||
LL| | right_comb_tree(false, false, false, true, true);
|
||||
LL| | right_comb_tree(true, false, false, true, true);
|
||||
LL| | right_comb_tree(true, true, true, true, true);
|
||||
LL| |
|
||||
LL| | func_call(true, false);
|
||||
LL| | func_call(true, true);
|
||||
LL| | func_call(false, false);
|
||||
LL| |}
|
||||
|
72
tests/coverage/mcdc_non_control_flow.rs
Normal file
72
tests/coverage/mcdc_non_control_flow.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ min-llvm-version: 18
|
||||
//@ compile-flags: -Zcoverage-options=mcdc
|
||||
//@ llvm-cov-flags: --show-mcdc
|
||||
|
||||
// This test ensures that boolean expressions that are not inside control flow
|
||||
// decisions are correctly instrumented.
|
||||
|
||||
use core::hint::black_box;
|
||||
|
||||
fn assign_and(a: bool, b: bool) {
|
||||
let x = a && b;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn assign_or(a: bool, b: bool) {
|
||||
let x = a || b;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn assign_3(a: bool, b: bool, c: bool) {
|
||||
let x = a || b && c;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn assign_3_bis(a: bool, b: bool, c: bool) {
|
||||
let x = a && b || c;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn right_comb_tree(a: bool, b: bool, c: bool, d: bool, e: bool) {
|
||||
let x = a && (b && (c && (d && (e))));
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn foo(a: bool) -> bool {
|
||||
black_box(a)
|
||||
}
|
||||
|
||||
fn func_call(a: bool, b: bool) {
|
||||
foo(a && b);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
assign_and(true, false);
|
||||
assign_and(true, true);
|
||||
assign_and(false, false);
|
||||
|
||||
assign_or(true, false);
|
||||
assign_or(true, true);
|
||||
assign_or(false, false);
|
||||
|
||||
assign_3(true, false, false);
|
||||
assign_3(true, true, false);
|
||||
assign_3(false, false, true);
|
||||
assign_3(false, true, true);
|
||||
|
||||
assign_3_bis(true, false, false);
|
||||
assign_3_bis(true, true, false);
|
||||
assign_3_bis(false, false, true);
|
||||
assign_3_bis(false, true, true);
|
||||
|
||||
right_comb_tree(false, false, false, true, true);
|
||||
right_comb_tree(true, false, false, true, true);
|
||||
right_comb_tree(true, true, true, true, true);
|
||||
|
||||
func_call(true, false);
|
||||
func_call(true, true);
|
||||
func_call(false, false);
|
||||
}
|
|
@ -2,58 +2,23 @@
|
|||
//! No hidden types are being constrained in the subtyping predicate, but type and
|
||||
//! lifetime variables get subtyped in the generic parameter list of the opaque.
|
||||
|
||||
use std::iter;
|
||||
//@ check-pass
|
||||
|
||||
mod either {
|
||||
pub enum Either<L, R> {
|
||||
Left(L),
|
||||
Right(R),
|
||||
}
|
||||
|
||||
impl<L: Iterator, R: Iterator<Item = L::Item>> Iterator for Either<L, R> {
|
||||
type Item = L::Item;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
pub use self::Either::{Left, Right};
|
||||
}
|
||||
|
||||
pub enum BabeConsensusLogRef<'a> {
|
||||
NextEpochData(BabeNextEpochRef<'a>),
|
||||
NextConfigData,
|
||||
}
|
||||
|
||||
impl<'a> BabeConsensusLogRef<'a> {
|
||||
pub fn scale_encoding(
|
||||
&self,
|
||||
) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
|
||||
//~^ ERROR is not satisfied
|
||||
//~| ERROR is not satisfied
|
||||
//~| ERROR is not satisfied
|
||||
match self {
|
||||
BabeConsensusLogRef::NextEpochData(digest) => either::Left(either::Left(
|
||||
digest.scale_encoding().map(either::Left).map(either::Left),
|
||||
)),
|
||||
BabeConsensusLogRef::NextConfigData => either::Right(
|
||||
// The Opaque type from ``scale_encoding` gets used opaquely here, while the `R`
|
||||
// generic parameter of `Either` contains type variables that get subtyped and the
|
||||
// opaque type contains lifetime variables that get subtyped.
|
||||
iter::once(either::Right(either::Left([1])))
|
||||
.chain(std::iter::once([1]).map(either::Right).map(either::Right)),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BabeNextEpochRef<'a>(&'a ());
|
||||
|
||||
impl<'a> BabeNextEpochRef<'a> {
|
||||
pub fn scale_encoding(
|
||||
&self,
|
||||
) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
|
||||
std::iter::once([1])
|
||||
fn foo() -> impl Default + Copy {
|
||||
if false {
|
||||
let x = Default::default();
|
||||
// add `Subtype(?x, ?y)` obligation
|
||||
let y = x;
|
||||
|
||||
// Make a tuple `(?x, ?y)` and equate it with `(impl Default, u32)`.
|
||||
// For us to try and prove a `Subtype(impl Default, u32)` obligation,
|
||||
// we have to instantiate both `?x` and `?y` without any
|
||||
// `select_where_possible` calls inbetween.
|
||||
let mut tup = &mut (x, y);
|
||||
let assign_tup = &mut (foo(), 1u32);
|
||||
tup = assign_tup;
|
||||
}
|
||||
1u32
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
error[E0277]: the trait bound `Either<Either<Map<Map<impl Iterator<Item = impl AsRef<[u8]> + Clone + '_> + Clone + '_, fn(impl AsRef<[u8]> + Clone + '_) -> Either<impl AsRef<[u8]> + Clone + '_, _> {Either::<impl AsRef<[u8]> + Clone + '_, _>::Left}>, fn(Either<impl AsRef<[u8]> + Clone + '_, _>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Left}>, _>, std::iter::Chain<std::iter::Once<Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>>, Map<Map<std::iter::Once<[{integer}; 1]>, fn([{integer}; 1]) -> Either<[{integer}; 1], [{integer}; 1]> {Either::<[{integer}; 1], [{integer}; 1]>::Right}>, fn(Either<[{integer}; 1], [{integer}; 1]>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Right}>>>: Clone` is not satisfied
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:30:10
|
||||
|
|
||||
LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Either<Either<Map<Map<impl Iterator<Item = impl AsRef<[u8]> + Clone + '_> + Clone + '_, fn(impl AsRef<[u8]> + Clone + '_) -> Either<impl AsRef<[u8]> + Clone + '_, _> {Either::<impl AsRef<[u8]> + Clone + '_, _>::Left}>, fn(Either<impl AsRef<[u8]> + Clone + '_, _>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Left}>, _>, std::iter::Chain<std::iter::Once<Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>>, Map<Map<std::iter::Once<[{integer}; 1]>, fn([{integer}; 1]) -> Either<[{integer}; 1], [{integer}; 1]> {Either::<[{integer}; 1], [{integer}; 1]>::Right}>, fn(Either<[{integer}; 1], [{integer}; 1]>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Right}>>>`
|
||||
|
||||
error[E0277]: the trait bound `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>: AsRef<[u8]>` is not satisfied
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:30:31
|
||||
|
|
||||
LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsRef<[u8]>` is not implemented for `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>`
|
||||
|
||||
error[E0277]: the trait bound `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>: Clone` is not satisfied
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:30:31
|
||||
|
|
||||
LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
|
@ -7,9 +7,10 @@
|
|||
type Tait = impl FnOnce() -> ();
|
||||
|
||||
fn reify_as_tait() -> Thunk<Tait> {
|
||||
//~^ ERROR: expected a `FnOnce()` closure, found `()`
|
||||
Thunk::new(|cont| cont)
|
||||
//~^ ERROR: mismatched types
|
||||
//~| ERROR: mismatched types
|
||||
//~| ERROR: expected a `FnOnce()` closure, found `()`
|
||||
}
|
||||
|
||||
struct Thunk<F>(F);
|
||||
|
|
|
@ -1,26 +1,31 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:10:23
|
||||
error[E0277]: expected a `FnOnce()` closure, found `()`
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:11:23
|
||||
|
|
||||
LL | type Tait = impl FnOnce() -> ();
|
||||
| ------------------- the found opaque type
|
||||
...
|
||||
LL | Thunk::new(|cont| cont)
|
||||
| ^^^^ expected `()`, found opaque type
|
||||
| ^^^^ expected an `FnOnce()` closure, found `()`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found opaque type `Tait`
|
||||
= help: the trait `FnOnce()` is not implemented for `()`
|
||||
= note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:10:5
|
||||
error[E0277]: expected a `FnOnce()` closure, found `()`
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:9:23
|
||||
|
|
||||
LL | fn reify_as_tait() -> Thunk<Tait> {
|
||||
| ----------- expected `Thunk<_>` because of return type
|
||||
| ^^^^^^^^^^^ expected an `FnOnce()` closure, found `()`
|
||||
|
|
||||
= help: the trait `FnOnce()` is not implemented for `()`
|
||||
= note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/lazy_subtyping_of_opaques.rs:11:5
|
||||
|
|
||||
LL | Thunk::new(|cont| cont)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `Thunk<_>`, found `()`
|
||||
|
|
||||
= note: expected struct `Thunk<_>`
|
||||
found unit type `()`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
Loading…
Add table
Reference in a new issue