Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -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"
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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",
2 changes: 0 additions & 2 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
@@ -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
8 changes: 3 additions & 5 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
@@ -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(())
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
@@ -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))
}
})
}
11 changes: 7 additions & 4 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
@@ -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.
68 changes: 45 additions & 23 deletions compiler/rustc_mir_build/src/build/coverageinfo.rs
Original file line number Diff line number Diff line change
@@ -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);

self.branch_spans.push(BranchSpan { span: source_info.span, true_marker, false_marker });
// 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,
});
}
}

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,
);
}
}
3 changes: 3 additions & 0 deletions compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
@@ -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| {
14 changes: 14 additions & 0 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
@@ -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 {}",
4 changes: 1 addition & 3 deletions config.example.toml
Original file line number Diff line number Diff line change
@@ -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
1 change: 0 additions & 1 deletion src/bootstrap/src/core/build_steps/clippy.rs
Original file line number Diff line number Diff line change
@@ -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";
93 changes: 3 additions & 90 deletions src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
@@ -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");
}
16 changes: 0 additions & 16 deletions src/bootstrap/src/core/build_steps/install.rs
Original file line number Diff line number Diff line change
@@ -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),
59 changes: 0 additions & 59 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
@@ -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,
1 change: 0 additions & 1 deletion src/bootstrap/src/core/build_steps/tool.rs
Original file line number Diff line number Diff line change
@@ -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"];
);

28 changes: 6 additions & 22 deletions src/bootstrap/src/core/builder.rs
Original file line number Diff line number Diff line change
@@ -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}")
18 changes: 17 additions & 1 deletion src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
@@ -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);
}

5 changes: 0 additions & 5 deletions src/bootstrap/src/utils/tarball.rs
Original file line number Diff line number Diff line change
@@ -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"))
}
8 changes: 1 addition & 7 deletions src/doc/rustc/src/instrument-coverage.md
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions src/tools/miri/tests/fail/storage-live-dead-var.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions src/tools/miri/tests/fail/storage-live-dead-var.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions src/tools/miri/tests/fail/storage-live-resets-var.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions src/tools/miri/tests/fail/storage-live-resets-var.stderr
Original file line number Diff line number Diff line change
@@ -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

16 changes: 0 additions & 16 deletions src/tools/rust-demangler/Cargo.toml

This file was deleted.

36 changes: 0 additions & 36 deletions src/tools/rust-demangler/README.md

This file was deleted.

21 changes: 0 additions & 21 deletions src/tools/rust-demangler/src/lib.rs

This file was deleted.

97 changes: 0 additions & 97 deletions src/tools/rust-demangler/src/main.rs

This file was deleted.

84 changes: 0 additions & 84 deletions src/tools/rust-demangler/tests/lib.rs

This file was deleted.

204 changes: 204 additions & 0 deletions tests/coverage/mcdc_non_control_flow.cov-map
Original file line number Diff line number Diff line change
@@ -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 changes: 202 additions & 0 deletions tests/coverage/mcdc_non_control_flow.coverage
Original file line number Diff line number Diff line change
@@ -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 changes: 72 additions & 0 deletions tests/coverage/mcdc_non_control_flow.rs
Original file line number Diff line number Diff line change
@@ -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);
}
67 changes: 16 additions & 51 deletions tests/ui/impl-trait/lazy_subtyping_of_opaques.rs
Original file line number Diff line number Diff line change
@@ -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;

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])
//@ check-pass

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() {}
21 changes: 0 additions & 21 deletions tests/ui/impl-trait/lazy_subtyping_of_opaques.stderr

This file was deleted.

3 changes: 2 additions & 1 deletion tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.rs
Original file line number Diff line number Diff line change
@@ -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);
31 changes: 18 additions & 13 deletions tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr
Original file line number Diff line number Diff line change
@@ -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`.