mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-21 20:23:21 +00:00
Auto merge of #125732 - matthiaskrgr:rollup-bozbtk3, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #124655 (Add `-Zfixed-x18`) - #125693 (Format all source files in `tests/coverage/`) - #125700 (coverage: Avoid overflow when the MC/DC condition limit is exceeded) - #125705 (Reintroduce name resolution check for trying to access locals from an inline const) - #125708 (tier 3 target policy: clarify the point about producing assembly) - #125715 (remove unneeded extern crate in rmake test) - #125719 (Extract coverage-specific code out of `compiletest::runtest`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
debd22da66
@ -18,6 +18,8 @@ codegen_llvm_error_creating_import_library =
|
||||
codegen_llvm_error_writing_def_file =
|
||||
Error writing .DEF file: {$error}
|
||||
|
||||
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||
|
||||
codegen_llvm_from_llvm_diag = {$message}
|
||||
|
||||
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
|
||||
|
@ -254,3 +254,9 @@ pub struct MismatchedDataLayout<'a> {
|
||||
pub(crate) struct InvalidTargetFeaturePrefix<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_fixed_x18_invalid_arch)]
|
||||
pub(crate) struct FixedX18InvalidArch<'a> {
|
||||
pub arch: &'a str,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
|
||||
FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
|
||||
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
};
|
||||
use crate::llvm;
|
||||
@ -615,6 +615,15 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
|
||||
.flatten();
|
||||
features.extend(feats);
|
||||
|
||||
// -Zfixed-x18
|
||||
if sess.opts.unstable_opts.fixed_x18 {
|
||||
if sess.target.arch != "aarch64" {
|
||||
sess.dcx().emit_fatal(FixedX18InvalidArch { arch: &sess.target.arch });
|
||||
} else {
|
||||
features.push("+reserve-x18".into());
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
|
@ -773,6 +773,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(emit_thin_lto, false);
|
||||
tracked!(export_executable_symbols, true);
|
||||
tracked!(fewer_names, Some(true));
|
||||
tracked!(fixed_x18, true);
|
||||
tracked!(flatten_format_args, false);
|
||||
tracked!(force_unstable_if_unmarked, true);
|
||||
tracked!(fuel, Some(("abc".to_string(), 99)));
|
||||
|
@ -217,12 +217,13 @@ impl MCDCInfoBuilder {
|
||||
}
|
||||
_ => {
|
||||
// Do not generate mcdc mappings and statements for decisions with too many conditions.
|
||||
let rebase_idx = self.branch_spans.len() - decision.conditions_num + 1;
|
||||
// Therefore, first erase the condition info of the (N-1) previous branch spans.
|
||||
let rebase_idx = self.branch_spans.len() - (decision.conditions_num - 1);
|
||||
for branch in &mut self.branch_spans[rebase_idx..] {
|
||||
branch.condition_info = None;
|
||||
}
|
||||
|
||||
// ConditionInfo of this branch shall also be reset.
|
||||
// Then, erase this last branch span's info too, for a total of N.
|
||||
condition_info = None;
|
||||
|
||||
tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit {
|
||||
|
@ -4505,6 +4505,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
self.visit_expr(elem);
|
||||
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
|
||||
}
|
||||
ExprKind::ConstBlock(ref expr) => {
|
||||
self.resolve_anon_const_manual(false, AnonConstKind::InlineConst, |this| {
|
||||
this.visit_expr(expr)
|
||||
});
|
||||
}
|
||||
ExprKind::Index(ref elem, ref idx, _) => {
|
||||
self.resolve_expr(elem, Some(expr));
|
||||
self.visit_expr(idx);
|
||||
|
@ -1678,6 +1678,8 @@ options! {
|
||||
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
|
||||
(default: no)"),
|
||||
fixed_x18: bool = (false, parse_bool, [TRACKED],
|
||||
"make the x18 register reserved on AArch64 (default: no)"),
|
||||
flatten_format_args: bool = (true, parse_bool, [TRACKED],
|
||||
"flatten nested format_args!() and literals into a simplified format_args!() call \
|
||||
(default: yes)"),
|
||||
|
@ -247,7 +247,8 @@ approved by the appropriate team for that shared code before acceptance.
|
||||
target may not have; use conditional compilation or runtime detection, as
|
||||
appropriate, to let each target run code supported by that target.
|
||||
- Tier 3 targets must be able to produce assembly using at least one of
|
||||
rustc's supported backends from any host target.
|
||||
rustc's supported backends from any host target. (Having support in a fork
|
||||
of the backend is not sufficient, it must be upstream.)
|
||||
|
||||
If a tier 3 target stops meeting these requirements, or the target maintainers
|
||||
no longer have interest or time, or the target shows no signs of activity and
|
||||
|
32
src/doc/unstable-book/src/compiler-flags/fixed-x18.md
Normal file
32
src/doc/unstable-book/src/compiler-flags/fixed-x18.md
Normal file
@ -0,0 +1,32 @@
|
||||
# `fixed-x18`
|
||||
|
||||
This option prevents the compiler from using the x18 register. It is only
|
||||
supported on aarch64.
|
||||
|
||||
From the [ABI spec][arm-abi]:
|
||||
|
||||
> X18 is the platform register and is reserved for the use of platform ABIs.
|
||||
> This is an additional temporary register on platforms that don't assign a
|
||||
> special meaning to it.
|
||||
|
||||
This flag only has an effect when the x18 register would otherwise be considered
|
||||
a temporary register. When the flag is applied, x18 is always a reserved
|
||||
register.
|
||||
|
||||
This flag is intended for use with the shadow call stack sanitizer. Generally,
|
||||
when that sanitizer is enabled, the x18 register is used to store a pointer to
|
||||
the shadow stack. Enabling this flag prevents the compiler from overwriting the
|
||||
shadow stack pointer with temporary data, which is necessary for the sanitizer
|
||||
to work correctly.
|
||||
|
||||
Currently, the `-Zsanitizer=shadow-call-stack` flag is only supported on
|
||||
platforms that always treat x18 as a reserved register, and the `-Zfixed-x18`
|
||||
flag is not required to use the sanitizer on such platforms. However, the
|
||||
sanitizer may be supported on targets where this is not the case in the future.
|
||||
|
||||
It is undefined behavior for `-Zsanitizer=shadow-call-stack` code to call into
|
||||
code where x18 is a temporary register. On the other hand, when you are *not*
|
||||
using the shadow call stack sanitizer, compilation units compiled with and
|
||||
without the `-Zfixed-x18` flag are compatible with each other.
|
||||
|
||||
[arm-abi]: https://developer.arm.com/documentation/den0024/a/The-ABI-for-ARM-64-bit-Architecture/Register-use-in-the-AArch64-Procedure-Call-Standard/Parameters-in-general-purpose-registers
|
@ -9,7 +9,7 @@ use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc};
|
||||
use crate::common::{CompareMode, FailMode, PassMode};
|
||||
use crate::common::{Config, TestPaths};
|
||||
use crate::common::{CoverageMap, CoverageRun, Pretty, RunPassValgrind};
|
||||
use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP, UI_RUN_STDERR, UI_RUN_STDOUT};
|
||||
use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT};
|
||||
use crate::compute_diff::{write_diff, write_filtered_diff};
|
||||
use crate::errors::{self, Error, ErrorKind};
|
||||
use crate::header::TestProps;
|
||||
@ -41,6 +41,7 @@ use tracing::*;
|
||||
use crate::extract_gdb_version;
|
||||
use crate::is_android_gdb_target;
|
||||
|
||||
mod coverage;
|
||||
mod debugger;
|
||||
use debugger::DebuggerCommands;
|
||||
|
||||
@ -53,6 +54,7 @@ macro_rules! static_regex {
|
||||
RE.get_or_init(|| ::regex::Regex::new($re).unwrap())
|
||||
}};
|
||||
}
|
||||
use static_regex;
|
||||
|
||||
const FAKE_SRC_BASE: &str = "fake-test-src-base";
|
||||
|
||||
@ -267,8 +269,8 @@ impl<'test> TestCx<'test> {
|
||||
MirOpt => self.run_mir_opt_test(),
|
||||
Assembly => self.run_assembly_test(),
|
||||
JsDocTest => self.run_js_doc_test(),
|
||||
CoverageMap => self.run_coverage_map_test(),
|
||||
CoverageRun => self.run_coverage_run_test(),
|
||||
CoverageMap => self.run_coverage_map_test(), // see self::coverage
|
||||
CoverageRun => self.run_coverage_run_test(), // see self::coverage
|
||||
Crashes => self.run_crash_test(),
|
||||
}
|
||||
}
|
||||
@ -504,224 +506,6 @@ impl<'test> TestCx<'test> {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_coverage_map_test(&self) {
|
||||
let Some(coverage_dump_path) = &self.config.coverage_dump_path else {
|
||||
self.fatal("missing --coverage-dump");
|
||||
};
|
||||
|
||||
let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir();
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
let mut dump_command = Command::new(coverage_dump_path);
|
||||
dump_command.arg(llvm_ir_path);
|
||||
let proc_res = self.run_command_to_procres(&mut dump_command);
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("coverage-dump failed!", &proc_res);
|
||||
}
|
||||
|
||||
let kind = UI_COVERAGE_MAP;
|
||||
|
||||
let expected_coverage_dump = self.load_expected_output(kind);
|
||||
let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]);
|
||||
|
||||
let coverage_dump_errors =
|
||||
self.compare_output(kind, &actual_coverage_dump, &expected_coverage_dump);
|
||||
|
||||
if coverage_dump_errors > 0 {
|
||||
self.fatal_proc_rec(
|
||||
&format!("{coverage_dump_errors} errors occurred comparing coverage output."),
|
||||
&proc_res,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_coverage_run_test(&self) {
|
||||
let should_run = self.run_if_enabled();
|
||||
let proc_res = self.compile_test(should_run, Emit::None);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let profraw_path = self.output_base_dir().join("default.profraw");
|
||||
let profdata_path = self.output_base_dir().join("default.profdata");
|
||||
|
||||
// Delete any existing profraw/profdata files to rule out unintended
|
||||
// interference between repeated test runs.
|
||||
if profraw_path.exists() {
|
||||
std::fs::remove_file(&profraw_path).unwrap();
|
||||
}
|
||||
if profdata_path.exists() {
|
||||
std::fs::remove_file(&profdata_path).unwrap();
|
||||
}
|
||||
|
||||
let proc_res = self.exec_compiled_test_general(
|
||||
&[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())],
|
||||
false,
|
||||
);
|
||||
if self.props.failure_status.is_some() {
|
||||
self.check_correct_failure_status(&proc_res);
|
||||
} else if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
let mut profraw_paths = vec![profraw_path];
|
||||
let mut bin_paths = vec![self.make_exe_name()];
|
||||
|
||||
if self.config.suite == "coverage-run-rustdoc" {
|
||||
self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths);
|
||||
}
|
||||
|
||||
// Run `llvm-profdata merge` to index the raw coverage output.
|
||||
let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| {
|
||||
cmd.args(["merge", "--sparse", "--output"]);
|
||||
cmd.arg(&profdata_path);
|
||||
cmd.args(&profraw_paths);
|
||||
});
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
// Run `llvm-cov show` to produce a coverage report in text format.
|
||||
let proc_res = self.run_llvm_tool("llvm-cov", |cmd| {
|
||||
cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]);
|
||||
|
||||
cmd.arg("--Xdemangler");
|
||||
cmd.arg(self.config.rust_demangler_path.as_ref().unwrap());
|
||||
|
||||
cmd.arg("--instr-profile");
|
||||
cmd.arg(&profdata_path);
|
||||
|
||||
for bin in &bin_paths {
|
||||
cmd.arg("--object");
|
||||
cmd.arg(bin);
|
||||
}
|
||||
|
||||
cmd.args(&self.props.llvm_cov_flags);
|
||||
});
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("llvm-cov show failed!", &proc_res);
|
||||
}
|
||||
|
||||
let kind = UI_COVERAGE;
|
||||
|
||||
let expected_coverage = self.load_expected_output(kind);
|
||||
let normalized_actual_coverage =
|
||||
self.normalize_coverage_output(&proc_res.stdout).unwrap_or_else(|err| {
|
||||
self.fatal_proc_rec(&err, &proc_res);
|
||||
});
|
||||
|
||||
let coverage_errors =
|
||||
self.compare_output(kind, &normalized_actual_coverage, &expected_coverage);
|
||||
|
||||
if coverage_errors > 0 {
|
||||
self.fatal_proc_rec(
|
||||
&format!("{} errors occurred comparing coverage output.", coverage_errors),
|
||||
&proc_res,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Run any doctests embedded in this test file, and add any resulting
|
||||
/// `.profraw` files and doctest executables to the given vectors.
|
||||
fn run_doctests_for_coverage(
|
||||
&self,
|
||||
profraw_paths: &mut Vec<PathBuf>,
|
||||
bin_paths: &mut Vec<PathBuf>,
|
||||
) {
|
||||
// Put .profraw files and doctest executables in dedicated directories,
|
||||
// to make it easier to glob them all later.
|
||||
let profraws_dir = self.output_base_dir().join("doc_profraws");
|
||||
let bins_dir = self.output_base_dir().join("doc_bins");
|
||||
|
||||
// Remove existing directories to prevent cross-run interference.
|
||||
if profraws_dir.try_exists().unwrap() {
|
||||
std::fs::remove_dir_all(&profraws_dir).unwrap();
|
||||
}
|
||||
if bins_dir.try_exists().unwrap() {
|
||||
std::fs::remove_dir_all(&bins_dir).unwrap();
|
||||
}
|
||||
|
||||
let mut rustdoc_cmd =
|
||||
Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed"));
|
||||
|
||||
// In general there will be multiple doctest binaries running, so we
|
||||
// tell the profiler runtime to write their coverage data into separate
|
||||
// profraw files.
|
||||
rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw"));
|
||||
|
||||
rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]);
|
||||
|
||||
// Without this, the doctests complain about not being able to find
|
||||
// their enclosing file's crate for some reason.
|
||||
rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]);
|
||||
|
||||
// Persist the doctest binaries so that `llvm-cov show` can read their
|
||||
// embedded coverage mappings later.
|
||||
rustdoc_cmd.arg("-Zunstable-options");
|
||||
rustdoc_cmd.arg("--persist-doctests");
|
||||
rustdoc_cmd.arg(&bins_dir);
|
||||
|
||||
rustdoc_cmd.arg("-L");
|
||||
rustdoc_cmd.arg(self.aux_output_dir_name());
|
||||
|
||||
rustdoc_cmd.arg(&self.testpaths.file);
|
||||
|
||||
let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None);
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
|
||||
}
|
||||
|
||||
fn glob_iter(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
||||
let path_str = path.as_ref().to_str().unwrap();
|
||||
let iter = glob(path_str).unwrap();
|
||||
iter.map(Result::unwrap)
|
||||
}
|
||||
|
||||
// Find all profraw files in the profraw directory.
|
||||
for p in glob_iter(profraws_dir.join("*.profraw")) {
|
||||
profraw_paths.push(p);
|
||||
}
|
||||
// Find all executables in the `--persist-doctests` directory, while
|
||||
// avoiding other file types (e.g. `.pdb` on Windows). This doesn't
|
||||
// need to be perfect, as long as it can handle the files actually
|
||||
// produced by `rustdoc --test`.
|
||||
for p in glob_iter(bins_dir.join("**/*")) {
|
||||
let is_bin = p.is_file()
|
||||
&& match p.extension() {
|
||||
None => true,
|
||||
Some(ext) => ext == OsStr::new("exe"),
|
||||
};
|
||||
if is_bin {
|
||||
bin_paths.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes {
|
||||
let tool_path = self
|
||||
.config
|
||||
.llvm_bin_dir
|
||||
.as_ref()
|
||||
.expect("this test expects the LLVM bin dir to be available")
|
||||
.join(name);
|
||||
|
||||
let mut cmd = Command::new(tool_path);
|
||||
configure_cmd_fn(&mut cmd);
|
||||
|
||||
self.run_command_to_procres(&mut cmd)
|
||||
}
|
||||
|
||||
fn run_command_to_procres(&self, cmd: &mut Command) -> ProcRes {
|
||||
let output = cmd.output().unwrap_or_else(|e| panic!("failed to exec `{cmd:?}`: {e:?}"));
|
||||
|
||||
@ -737,143 +521,6 @@ impl<'test> TestCx<'test> {
|
||||
proc_res
|
||||
}
|
||||
|
||||
fn normalize_coverage_output(&self, coverage: &str) -> Result<String, String> {
|
||||
let normalized = self.normalize_output(coverage, &[]);
|
||||
let normalized = Self::anonymize_coverage_line_numbers(&normalized);
|
||||
|
||||
let mut lines = normalized.lines().collect::<Vec<_>>();
|
||||
|
||||
Self::sort_coverage_file_sections(&mut lines)?;
|
||||
Self::sort_coverage_subviews(&mut lines)?;
|
||||
|
||||
let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::<String>();
|
||||
Ok(joined_lines)
|
||||
}
|
||||
|
||||
/// Replace line numbers in coverage reports with the placeholder `LL`,
|
||||
/// so that the tests are less sensitive to lines being added/removed.
|
||||
fn anonymize_coverage_line_numbers(coverage: &str) -> String {
|
||||
// The coverage reporter prints line numbers at the start of a line.
|
||||
// They are truncated or left-padded to occupy exactly 5 columns.
|
||||
// (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.)
|
||||
// A pipe character `|` appears immediately after the final digit.
|
||||
//
|
||||
// Line numbers that appear inside expansion/instantiation subviews
|
||||
// have an additional prefix of ` |` for each nesting level.
|
||||
//
|
||||
// Branch views also include the relevant line number, so we want to
|
||||
// redact those too. (These line numbers don't have padding.)
|
||||
//
|
||||
// Note: The pattern `(?m:^)` matches the start of a line.
|
||||
|
||||
// ` 1|` => ` LL|`
|
||||
// ` 10|` => ` LL|`
|
||||
// ` 100|` => ` LL|`
|
||||
// ` | 1000|` => ` | LL|`
|
||||
// ` | | 1000|` => ` | | LL|`
|
||||
let coverage = static_regex!(r"(?m:^)(?<prefix>(?: \|)*) *[0-9]+\|")
|
||||
.replace_all(&coverage, "${prefix} LL|");
|
||||
|
||||
// ` | Branch (1:` => ` | Branch (LL:`
|
||||
// ` | | Branch (10:` => ` | | Branch (LL:`
|
||||
let coverage = static_regex!(r"(?m:^)(?<prefix>(?: \|)+ Branch \()[0-9]+:")
|
||||
.replace_all(&coverage, "${prefix}LL:");
|
||||
|
||||
// ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:`
|
||||
let coverage =
|
||||
static_regex!(r"(?m:^)(?<prefix>(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?<middle>[0-9]+\) to \()[0-9]+:")
|
||||
.replace_all(&coverage, "${prefix}LL:${middle}LL:");
|
||||
|
||||
// ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:`
|
||||
let coverage =
|
||||
static_regex!(r"(?m:^)(?<prefix>(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:")
|
||||
.replace_all(&coverage, "${prefix}LL:");
|
||||
|
||||
coverage.into_owned()
|
||||
}
|
||||
|
||||
/// Coverage reports can describe multiple source files, separated by
|
||||
/// blank lines. The order of these files is unpredictable (since it
|
||||
/// depends on implementation details), so we need to sort the file
|
||||
/// sections into a consistent order before comparing against a snapshot.
|
||||
fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> {
|
||||
// Group the lines into file sections, separated by blank lines.
|
||||
let mut sections = coverage_lines.split(|line| line.is_empty()).collect::<Vec<_>>();
|
||||
|
||||
// The last section should be empty, representing an extra trailing blank line.
|
||||
if !sections.last().is_some_and(|last| last.is_empty()) {
|
||||
return Err("coverage report should end with an extra blank line".to_owned());
|
||||
}
|
||||
|
||||
// Sort the file sections (not including the final empty "section").
|
||||
let except_last = sections.len() - 1;
|
||||
(&mut sections[..except_last]).sort();
|
||||
|
||||
// Join the file sections back into a flat list of lines, with
|
||||
// sections separated by blank lines.
|
||||
let joined = sections.join(&[""] as &[_]);
|
||||
assert_eq!(joined.len(), coverage_lines.len());
|
||||
*coverage_lines = joined;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> {
|
||||
let mut output_lines = Vec::new();
|
||||
|
||||
// We accumulate a list of zero or more "subviews", where each
|
||||
// subview is a list of one or more lines.
|
||||
let mut subviews: Vec<Vec<&str>> = Vec::new();
|
||||
|
||||
fn flush<'a>(subviews: &mut Vec<Vec<&'a str>>, output_lines: &mut Vec<&'a str>) {
|
||||
if subviews.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Take and clear the list of accumulated subviews.
|
||||
let mut subviews = std::mem::take(subviews);
|
||||
|
||||
// The last "subview" should be just a boundary line on its own,
|
||||
// so exclude it when sorting the other subviews.
|
||||
let except_last = subviews.len() - 1;
|
||||
(&mut subviews[..except_last]).sort();
|
||||
|
||||
for view in subviews {
|
||||
for line in view {
|
||||
output_lines.push(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (line, line_num) in coverage_lines.iter().zip(1..) {
|
||||
if line.starts_with(" ------------------") {
|
||||
// This is a subview boundary line, so start a new subview.
|
||||
subviews.push(vec![line]);
|
||||
} else if line.starts_with(" |") {
|
||||
// Add this line to the current subview.
|
||||
subviews
|
||||
.last_mut()
|
||||
.ok_or(format!(
|
||||
"unexpected subview line outside of a subview on line {line_num}"
|
||||
))?
|
||||
.push(line);
|
||||
} else {
|
||||
// This line is not part of a subview, so sort and print any
|
||||
// accumulated subviews, and then print the line as-is.
|
||||
flush(&mut subviews, &mut output_lines);
|
||||
output_lines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
flush(&mut subviews, &mut output_lines);
|
||||
assert!(subviews.is_empty());
|
||||
|
||||
assert_eq!(output_lines.len(), coverage_lines.len());
|
||||
*coverage_lines = output_lines;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_pretty_test(&self) {
|
||||
if self.props.pp_exact.is_some() {
|
||||
logv(self.config, "testing for exact pretty-printing".to_owned());
|
||||
|
367
src/tools/compiletest/src/runtest/coverage.rs
Normal file
367
src/tools/compiletest/src/runtest/coverage.rs
Normal file
@ -0,0 +1,367 @@
|
||||
//! Code specific to the coverage test suites.
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use glob::glob;
|
||||
|
||||
use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP};
|
||||
use crate::runtest::{static_regex, Emit, ProcRes, TestCx, WillExecute};
|
||||
|
||||
impl<'test> TestCx<'test> {
|
||||
pub(crate) fn run_coverage_map_test(&self) {
|
||||
let Some(coverage_dump_path) = &self.config.coverage_dump_path else {
|
||||
self.fatal("missing --coverage-dump");
|
||||
};
|
||||
|
||||
let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir();
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
let mut dump_command = Command::new(coverage_dump_path);
|
||||
dump_command.arg(llvm_ir_path);
|
||||
let proc_res = self.run_command_to_procres(&mut dump_command);
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("coverage-dump failed!", &proc_res);
|
||||
}
|
||||
|
||||
let kind = UI_COVERAGE_MAP;
|
||||
|
||||
let expected_coverage_dump = self.load_expected_output(kind);
|
||||
let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]);
|
||||
|
||||
let coverage_dump_errors =
|
||||
self.compare_output(kind, &actual_coverage_dump, &expected_coverage_dump);
|
||||
|
||||
if coverage_dump_errors > 0 {
|
||||
self.fatal_proc_rec(
|
||||
&format!("{coverage_dump_errors} errors occurred comparing coverage output."),
|
||||
&proc_res,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_coverage_run_test(&self) {
|
||||
let should_run = self.run_if_enabled();
|
||||
let proc_res = self.compile_test(should_run, Emit::None);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let profraw_path = self.output_base_dir().join("default.profraw");
|
||||
let profdata_path = self.output_base_dir().join("default.profdata");
|
||||
|
||||
// Delete any existing profraw/profdata files to rule out unintended
|
||||
// interference between repeated test runs.
|
||||
if profraw_path.exists() {
|
||||
std::fs::remove_file(&profraw_path).unwrap();
|
||||
}
|
||||
if profdata_path.exists() {
|
||||
std::fs::remove_file(&profdata_path).unwrap();
|
||||
}
|
||||
|
||||
let proc_res = self.exec_compiled_test_general(
|
||||
&[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())],
|
||||
false,
|
||||
);
|
||||
if self.props.failure_status.is_some() {
|
||||
self.check_correct_failure_status(&proc_res);
|
||||
} else if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
let mut profraw_paths = vec![profraw_path];
|
||||
let mut bin_paths = vec![self.make_exe_name()];
|
||||
|
||||
if self.config.suite == "coverage-run-rustdoc" {
|
||||
self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths);
|
||||
}
|
||||
|
||||
// Run `llvm-profdata merge` to index the raw coverage output.
|
||||
let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| {
|
||||
cmd.args(["merge", "--sparse", "--output"]);
|
||||
cmd.arg(&profdata_path);
|
||||
cmd.args(&profraw_paths);
|
||||
});
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res);
|
||||
}
|
||||
drop(proc_res);
|
||||
|
||||
// Run `llvm-cov show` to produce a coverage report in text format.
|
||||
let proc_res = self.run_llvm_tool("llvm-cov", |cmd| {
|
||||
cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]);
|
||||
|
||||
cmd.arg("--Xdemangler");
|
||||
cmd.arg(self.config.rust_demangler_path.as_ref().unwrap());
|
||||
|
||||
cmd.arg("--instr-profile");
|
||||
cmd.arg(&profdata_path);
|
||||
|
||||
for bin in &bin_paths {
|
||||
cmd.arg("--object");
|
||||
cmd.arg(bin);
|
||||
}
|
||||
|
||||
cmd.args(&self.props.llvm_cov_flags);
|
||||
});
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("llvm-cov show failed!", &proc_res);
|
||||
}
|
||||
|
||||
let kind = UI_COVERAGE;
|
||||
|
||||
let expected_coverage = self.load_expected_output(kind);
|
||||
let normalized_actual_coverage =
|
||||
self.normalize_coverage_output(&proc_res.stdout).unwrap_or_else(|err| {
|
||||
self.fatal_proc_rec(&err, &proc_res);
|
||||
});
|
||||
|
||||
let coverage_errors =
|
||||
self.compare_output(kind, &normalized_actual_coverage, &expected_coverage);
|
||||
|
||||
if coverage_errors > 0 {
|
||||
self.fatal_proc_rec(
|
||||
&format!("{} errors occurred comparing coverage output.", coverage_errors),
|
||||
&proc_res,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Run any doctests embedded in this test file, and add any resulting
|
||||
/// `.profraw` files and doctest executables to the given vectors.
|
||||
fn run_doctests_for_coverage(
|
||||
&self,
|
||||
profraw_paths: &mut Vec<PathBuf>,
|
||||
bin_paths: &mut Vec<PathBuf>,
|
||||
) {
|
||||
// Put .profraw files and doctest executables in dedicated directories,
|
||||
// to make it easier to glob them all later.
|
||||
let profraws_dir = self.output_base_dir().join("doc_profraws");
|
||||
let bins_dir = self.output_base_dir().join("doc_bins");
|
||||
|
||||
// Remove existing directories to prevent cross-run interference.
|
||||
if profraws_dir.try_exists().unwrap() {
|
||||
std::fs::remove_dir_all(&profraws_dir).unwrap();
|
||||
}
|
||||
if bins_dir.try_exists().unwrap() {
|
||||
std::fs::remove_dir_all(&bins_dir).unwrap();
|
||||
}
|
||||
|
||||
let mut rustdoc_cmd =
|
||||
Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed"));
|
||||
|
||||
// In general there will be multiple doctest binaries running, so we
|
||||
// tell the profiler runtime to write their coverage data into separate
|
||||
// profraw files.
|
||||
rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw"));
|
||||
|
||||
rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]);
|
||||
|
||||
// Without this, the doctests complain about not being able to find
|
||||
// their enclosing file's crate for some reason.
|
||||
rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]);
|
||||
|
||||
// Persist the doctest binaries so that `llvm-cov show` can read their
|
||||
// embedded coverage mappings later.
|
||||
rustdoc_cmd.arg("-Zunstable-options");
|
||||
rustdoc_cmd.arg("--persist-doctests");
|
||||
rustdoc_cmd.arg(&bins_dir);
|
||||
|
||||
rustdoc_cmd.arg("-L");
|
||||
rustdoc_cmd.arg(self.aux_output_dir_name());
|
||||
|
||||
rustdoc_cmd.arg(&self.testpaths.file);
|
||||
|
||||
let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None);
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
|
||||
}
|
||||
|
||||
fn glob_iter(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
||||
let path_str = path.as_ref().to_str().unwrap();
|
||||
let iter = glob(path_str).unwrap();
|
||||
iter.map(Result::unwrap)
|
||||
}
|
||||
|
||||
// Find all profraw files in the profraw directory.
|
||||
for p in glob_iter(profraws_dir.join("*.profraw")) {
|
||||
profraw_paths.push(p);
|
||||
}
|
||||
// Find all executables in the `--persist-doctests` directory, while
|
||||
// avoiding other file types (e.g. `.pdb` on Windows). This doesn't
|
||||
// need to be perfect, as long as it can handle the files actually
|
||||
// produced by `rustdoc --test`.
|
||||
for p in glob_iter(bins_dir.join("**/*")) {
|
||||
let is_bin = p.is_file()
|
||||
&& match p.extension() {
|
||||
None => true,
|
||||
Some(ext) => ext == OsStr::new("exe"),
|
||||
};
|
||||
if is_bin {
|
||||
bin_paths.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes {
|
||||
let tool_path = self
|
||||
.config
|
||||
.llvm_bin_dir
|
||||
.as_ref()
|
||||
.expect("this test expects the LLVM bin dir to be available")
|
||||
.join(name);
|
||||
|
||||
let mut cmd = Command::new(tool_path);
|
||||
configure_cmd_fn(&mut cmd);
|
||||
|
||||
self.run_command_to_procres(&mut cmd)
|
||||
}
|
||||
|
||||
fn normalize_coverage_output(&self, coverage: &str) -> Result<String, String> {
|
||||
let normalized = self.normalize_output(coverage, &[]);
|
||||
let normalized = Self::anonymize_coverage_line_numbers(&normalized);
|
||||
|
||||
let mut lines = normalized.lines().collect::<Vec<_>>();
|
||||
|
||||
Self::sort_coverage_file_sections(&mut lines)?;
|
||||
Self::sort_coverage_subviews(&mut lines)?;
|
||||
|
||||
let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::<String>();
|
||||
Ok(joined_lines)
|
||||
}
|
||||
|
||||
/// Replace line numbers in coverage reports with the placeholder `LL`,
|
||||
/// so that the tests are less sensitive to lines being added/removed.
|
||||
fn anonymize_coverage_line_numbers(coverage: &str) -> String {
|
||||
// The coverage reporter prints line numbers at the start of a line.
|
||||
// They are truncated or left-padded to occupy exactly 5 columns.
|
||||
// (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.)
|
||||
// A pipe character `|` appears immediately after the final digit.
|
||||
//
|
||||
// Line numbers that appear inside expansion/instantiation subviews
|
||||
// have an additional prefix of ` |` for each nesting level.
|
||||
//
|
||||
// Branch views also include the relevant line number, so we want to
|
||||
// redact those too. (These line numbers don't have padding.)
|
||||
//
|
||||
// Note: The pattern `(?m:^)` matches the start of a line.
|
||||
|
||||
// ` 1|` => ` LL|`
|
||||
// ` 10|` => ` LL|`
|
||||
// ` 100|` => ` LL|`
|
||||
// ` | 1000|` => ` | LL|`
|
||||
// ` | | 1000|` => ` | | LL|`
|
||||
let coverage = static_regex!(r"(?m:^)(?<prefix>(?: \|)*) *[0-9]+\|")
|
||||
.replace_all(&coverage, "${prefix} LL|");
|
||||
|
||||
// ` | Branch (1:` => ` | Branch (LL:`
|
||||
// ` | | Branch (10:` => ` | | Branch (LL:`
|
||||
let coverage = static_regex!(r"(?m:^)(?<prefix>(?: \|)+ Branch \()[0-9]+:")
|
||||
.replace_all(&coverage, "${prefix}LL:");
|
||||
|
||||
// ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:`
|
||||
let coverage =
|
||||
static_regex!(r"(?m:^)(?<prefix>(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?<middle>[0-9]+\) to \()[0-9]+:")
|
||||
.replace_all(&coverage, "${prefix}LL:${middle}LL:");
|
||||
|
||||
// ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:`
|
||||
let coverage =
|
||||
static_regex!(r"(?m:^)(?<prefix>(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:")
|
||||
.replace_all(&coverage, "${prefix}LL:");
|
||||
|
||||
coverage.into_owned()
|
||||
}
|
||||
|
||||
/// Coverage reports can describe multiple source files, separated by
|
||||
/// blank lines. The order of these files is unpredictable (since it
|
||||
/// depends on implementation details), so we need to sort the file
|
||||
/// sections into a consistent order before comparing against a snapshot.
|
||||
fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> {
|
||||
// Group the lines into file sections, separated by blank lines.
|
||||
let mut sections = coverage_lines.split(|line| line.is_empty()).collect::<Vec<_>>();
|
||||
|
||||
// The last section should be empty, representing an extra trailing blank line.
|
||||
if !sections.last().is_some_and(|last| last.is_empty()) {
|
||||
return Err("coverage report should end with an extra blank line".to_owned());
|
||||
}
|
||||
|
||||
// Sort the file sections (not including the final empty "section").
|
||||
let except_last = sections.len() - 1;
|
||||
(&mut sections[..except_last]).sort();
|
||||
|
||||
// Join the file sections back into a flat list of lines, with
|
||||
// sections separated by blank lines.
|
||||
let joined = sections.join(&[""] as &[_]);
|
||||
assert_eq!(joined.len(), coverage_lines.len());
|
||||
*coverage_lines = joined;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> {
|
||||
let mut output_lines = Vec::new();
|
||||
|
||||
// We accumulate a list of zero or more "subviews", where each
|
||||
// subview is a list of one or more lines.
|
||||
let mut subviews: Vec<Vec<&str>> = Vec::new();
|
||||
|
||||
fn flush<'a>(subviews: &mut Vec<Vec<&'a str>>, output_lines: &mut Vec<&'a str>) {
|
||||
if subviews.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Take and clear the list of accumulated subviews.
|
||||
let mut subviews = std::mem::take(subviews);
|
||||
|
||||
// The last "subview" should be just a boundary line on its own,
|
||||
// so exclude it when sorting the other subviews.
|
||||
let except_last = subviews.len() - 1;
|
||||
(&mut subviews[..except_last]).sort();
|
||||
|
||||
for view in subviews {
|
||||
for line in view {
|
||||
output_lines.push(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (line, line_num) in coverage_lines.iter().zip(1..) {
|
||||
if line.starts_with(" ------------------") {
|
||||
// This is a subview boundary line, so start a new subview.
|
||||
subviews.push(vec![line]);
|
||||
} else if line.starts_with(" |") {
|
||||
// Add this line to the current subview.
|
||||
subviews
|
||||
.last_mut()
|
||||
.ok_or(format!(
|
||||
"unexpected subview line outside of a subview on line {line_num}"
|
||||
))?
|
||||
.push(line);
|
||||
} else {
|
||||
// This line is not part of a subview, so sort and print any
|
||||
// accumulated subviews, and then print the line as-is.
|
||||
flush(&mut subviews, &mut output_lines);
|
||||
output_lines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
flush(&mut subviews, &mut output_lines);
|
||||
assert!(subviews.is_empty());
|
||||
|
||||
assert_eq!(output_lines.len(), coverage_lines.len());
|
||||
*coverage_lines = output_lines;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -48,71 +48,3 @@ fn normalize_platform_differences() {
|
||||
r#"println!("test\ntest")"#,
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for anonymizing line numbers in coverage reports, especially for
|
||||
/// MC/DC regions.
|
||||
///
|
||||
/// FIXME(#123409): This test can be removed when we have examples of MC/DC
|
||||
/// coverage in the actual coverage test suite.
|
||||
#[test]
|
||||
fn anonymize_coverage_line_numbers() {
|
||||
let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage);
|
||||
|
||||
let input = r#"
|
||||
7| 2|fn mcdc_check_neither(a: bool, b: bool) {
|
||||
8| 2| if a && b {
|
||||
^0
|
||||
------------------
|
||||
|---> MC/DC Decision Region (8:8) to (8:14)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (8:8)
|
||||
| Condition C2 --> (8:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 0.00%
|
||||
|
|
||||
------------------
|
||||
9| 0| say("a and b");
|
||||
10| 2| } else {
|
||||
11| 2| say("not both");
|
||||
12| 2| }
|
||||
13| 2|}
|
||||
"#;
|
||||
|
||||
let expected = r#"
|
||||
LL| 2|fn mcdc_check_neither(a: bool, b: bool) {
|
||||
LL| 2| if a && b {
|
||||
^0
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:14)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 0.00%
|
||||
|
|
||||
------------------
|
||||
LL| 0| say("a and b");
|
||||
LL| 2| } else {
|
||||
LL| 2| say("not both");
|
||||
LL| 2| }
|
||||
LL| 2|}
|
||||
"#;
|
||||
|
||||
assert_eq!(anon(input), expected);
|
||||
}
|
||||
|
22
tests/codegen/fixed-x18.rs
Normal file
22
tests/codegen/fixed-x18.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Test that the `reserve-x18` target feature is (not) emitted when
|
||||
// the `-Zfixed-x18` flag is (not) set.
|
||||
|
||||
//@ revisions: unset set
|
||||
//@ needs-llvm-components: aarch64
|
||||
//@ compile-flags: --target aarch64-unknown-none
|
||||
//@ [set] compile-flags: -Zfixed-x18
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn foo() {
|
||||
// CHECK: @foo() unnamed_addr #0
|
||||
|
||||
// unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} }
|
||||
// set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} }
|
||||
}
|
@ -17,23 +17,23 @@ pub fn used_function() {
|
||||
}
|
||||
|
||||
pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
}
|
||||
// Expect for above function: `Unexecuted instantiation` (see below)
|
||||
pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
pub fn unused_generic_function<T: Debug>(arg: T) {
|
||||
println!("unused_generic_function with {:?}", arg);
|
||||
println!("unused_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
pub fn unused_function() {
|
||||
|
@ -31,28 +31,28 @@ pub fn used_inline_function() {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
}
|
||||
// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
|
||||
|
||||
#[inline(always)]
|
||||
pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn unused_generic_function<T: Debug>(arg: T) {
|
||||
println!("unused_generic_function with {:?}", arg);
|
||||
println!("unused_generic_function with {arg:?}");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -12,7 +12,7 @@ Number of file 0 mappings: 4
|
||||
- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
|
||||
|
||||
Function name: coroutine::main
|
||||
Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02]
|
||||
Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 8
|
||||
@ -26,7 +26,7 @@ Number of expressions: 8
|
||||
- expression 7 operands: lhs = Counter(4), rhs = Counter(5)
|
||||
Number of file 0 mappings: 9
|
||||
- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22)
|
||||
- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46)
|
||||
- Code(Counter(0)) at (prev + 8, 11) to (start + 0, 46)
|
||||
- Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45)
|
||||
- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 53)
|
||||
= ((c1 + c2) + c3)
|
||||
@ -41,11 +41,11 @@ Number of file 0 mappings: 9
|
||||
= ((c4 - c5) - c6)
|
||||
|
||||
Function name: coroutine::main::{closure#0}
|
||||
Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 29, 01, 1f, 05, 02, 10, 01, 06]
|
||||
Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 2
|
||||
- Code(Counter(0)) at (prev + 21, 41) to (start + 1, 31)
|
||||
- Code(Counter(0)) at (prev + 22, 8) to (start + 1, 31)
|
||||
- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6)
|
||||
|
||||
|
@ -10,15 +10,16 @@
|
||||
LL| |// to handle this condition, and still report dead block coverage.
|
||||
LL| 1|fn get_u32(val: bool) -> Result<u32, String> {
|
||||
LL| 1| if val {
|
||||
LL| 1| Ok(1)
|
||||
LL| 1| Ok(1) //
|
||||
LL| | } else {
|
||||
LL| 0| Err(String::from("some error"))
|
||||
LL| 0| Err(String::from("some error")) //
|
||||
LL| | }
|
||||
LL| 1|}
|
||||
LL| |
|
||||
LL| 1|fn main() {
|
||||
LL| 1| let is_true = std::env::args().len() == 1;
|
||||
LL| 1| let mut coroutine = #[coroutine] || {
|
||||
LL| 1| let mut coroutine = #[coroutine]
|
||||
LL| 1| || {
|
||||
LL| 1| yield get_u32(is_true);
|
||||
LL| 1| return "foo";
|
||||
LL| 1| };
|
||||
|
@ -10,15 +10,16 @@ use std::pin::Pin;
|
||||
// to handle this condition, and still report dead block coverage.
|
||||
fn get_u32(val: bool) -> Result<u32, String> {
|
||||
if val {
|
||||
Ok(1)
|
||||
Ok(1) //
|
||||
} else {
|
||||
Err(String::from("some error"))
|
||||
Err(String::from("some error")) //
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let is_true = std::env::args().len() == 1;
|
||||
let mut coroutine = #[coroutine] || {
|
||||
let mut coroutine = #[coroutine]
|
||||
|| {
|
||||
yield get_u32(is_true);
|
||||
return "foo";
|
||||
};
|
||||
|
@ -14,7 +14,7 @@
|
||||
LL| |#[inline]
|
||||
LL| 1|fn live<const B: bool>() -> u32 {
|
||||
LL| 1| if B {
|
||||
LL| 0| dead()
|
||||
LL| 0| dead() //
|
||||
LL| | } else {
|
||||
LL| 1| 0
|
||||
LL| | }
|
||||
|
@ -13,7 +13,7 @@ fn main() {
|
||||
#[inline]
|
||||
fn live<const B: bool>() -> u32 {
|
||||
if B {
|
||||
dead()
|
||||
dead() //
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
@ -52,7 +52,7 @@
|
||||
^0
|
||||
LL| |
|
||||
LL| 1| let mut val = InStruct {
|
||||
LL| 1| in_struct_field: 101,
|
||||
LL| 1| in_struct_field: 101, //
|
||||
LL| 1| };
|
||||
LL| 1|
|
||||
LL| 1| val.default_trait_func();
|
||||
|
@ -50,7 +50,7 @@ fn main() {
|
||||
}
|
||||
|
||||
let mut val = InStruct {
|
||||
in_struct_field: 101,
|
||||
in_struct_field: 101, //
|
||||
};
|
||||
|
||||
val.default_trait_func();
|
||||
|
@ -1,12 +1,12 @@
|
||||
Function name: let_else_loop::_if (unused)
|
||||
Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 02, 09, 00, 10, 00, 02, 09, 00, 10]
|
||||
Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 01, 0f, 00, 16, 00, 00, 20, 00, 27]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 3
|
||||
- Code(Zero) at (prev + 22, 1) to (start + 1, 12)
|
||||
- Code(Zero) at (prev + 2, 9) to (start + 0, 16)
|
||||
- Code(Zero) at (prev + 2, 9) to (start + 0, 16)
|
||||
- Code(Zero) at (prev + 1, 15) to (start + 0, 22)
|
||||
- Code(Zero) at (prev + 0, 32) to (start + 0, 39)
|
||||
|
||||
Function name: let_else_loop::_loop_either_way (unused)
|
||||
Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c]
|
||||
|
@ -21,11 +21,7 @@
|
||||
LL| |// Variant using regular `if` instead of let-else.
|
||||
LL| |// This doesn't trigger the original ICE, but might help detect regressions.
|
||||
LL| 0|fn _if(cond: bool) {
|
||||
LL| 0| if cond {
|
||||
LL| 0| loop {}
|
||||
LL| | } else {
|
||||
LL| 0| loop {}
|
||||
LL| | }
|
||||
LL| 0| if cond { loop {} } else { loop {} }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
|
@ -20,11 +20,7 @@ fn _loop_either_way(cond: bool) {
|
||||
// Variant using regular `if` instead of let-else.
|
||||
// This doesn't trigger the original ICE, but might help detect regressions.
|
||||
fn _if(cond: bool) {
|
||||
if cond {
|
||||
loop {}
|
||||
} else {
|
||||
loop {}
|
||||
}
|
||||
if cond { loop {} } else { loop {} }
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
|
162
tests/coverage/mcdc/condition-limit.cov-map
Normal file
162
tests/coverage/mcdc/condition-limit.cov-map
Normal file
@ -0,0 +1,162 @@
|
||||
Function name: condition_limit::bad
|
||||
Raw bytes (204): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 11, 01, 14, 01, 03, 09, 20, 05, 02, 03, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 7a, 1d, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 20, 76, 19, 00, 12, 00, 13, 76, 00, 17, 00, 18, 20, 72, 15, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 20, 6e, 11, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 20, 6a, 0d, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 20, 21, 09, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 44
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 3 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 4 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 5 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 6 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 7 operands: lhs = Expression(29, Sub), rhs = Counter(5)
|
||||
- expression 8 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 9 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 10 operands: lhs = Expression(29, Sub), rhs = Counter(5)
|
||||
- expression 11 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 12 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 13 operands: lhs = Expression(28, Sub), rhs = Counter(4)
|
||||
- expression 14 operands: lhs = Expression(29, Sub), rhs = Counter(5)
|
||||
- expression 15 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 16 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 17 operands: lhs = Expression(28, Sub), rhs = Counter(4)
|
||||
- expression 18 operands: lhs = Expression(29, Sub), rhs = Counter(5)
|
||||
- expression 19 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 20 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 21 operands: lhs = Expression(27, Sub), rhs = Counter(3)
|
||||
- expression 22 operands: lhs = Expression(28, Sub), rhs = Counter(4)
|
||||
- expression 23 operands: lhs = Expression(29, Sub), rhs = Counter(5)
|
||||
- expression 24 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 25 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 26 operands: lhs = Expression(27, Sub), rhs = Counter(3)
|
||||
- expression 27 operands: lhs = Expression(28, Sub), rhs = Counter(4)
|
||||
- expression 28 operands: lhs = Expression(29, Sub), rhs = Counter(5)
|
||||
- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(6)
|
||||
- expression 30 operands: lhs = Counter(1), rhs = Counter(7)
|
||||
- expression 31 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub)
|
||||
- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(7)
|
||||
- expression 33 operands: lhs = Expression(41, Add), rhs = Counter(6)
|
||||
- expression 34 operands: lhs = Expression(42, Add), rhs = Counter(5)
|
||||
- expression 35 operands: lhs = Expression(43, Add), rhs = Counter(4)
|
||||
- expression 36 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 37 operands: lhs = Counter(8), rhs = Expression(38, Add)
|
||||
- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub)
|
||||
- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(7)
|
||||
- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(6)
|
||||
- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(5)
|
||||
- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4)
|
||||
- expression 43 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
Number of file 0 mappings: 17
|
||||
- Code(Counter(0)) at (prev + 20, 1) to (start + 3, 9)
|
||||
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 3, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- Branch { true: Expression(30, Sub), false: Counter(7) } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = (c1 - c7)
|
||||
false = c7
|
||||
- Code(Expression(30, Sub)) at (prev + 0, 18) to (start + 0, 19)
|
||||
= (c1 - c7)
|
||||
- Branch { true: Expression(29, Sub), false: Counter(6) } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = ((c1 - c7) - c6)
|
||||
false = c6
|
||||
- Code(Expression(29, Sub)) at (prev + 0, 23) to (start + 0, 24)
|
||||
= ((c1 - c7) - c6)
|
||||
- Branch { true: Expression(28, Sub), false: Counter(5) } at (prev + 0, 23) to (start + 0, 24)
|
||||
true = (((c1 - c7) - c6) - c5)
|
||||
false = c5
|
||||
- Code(Expression(28, Sub)) at (prev + 0, 28) to (start + 0, 29)
|
||||
= (((c1 - c7) - c6) - c5)
|
||||
- Branch { true: Expression(27, Sub), false: Counter(4) } at (prev + 0, 28) to (start + 0, 29)
|
||||
true = ((((c1 - c7) - c6) - c5) - c4)
|
||||
false = c4
|
||||
- Code(Expression(27, Sub)) at (prev + 0, 33) to (start + 0, 34)
|
||||
= ((((c1 - c7) - c6) - c5) - c4)
|
||||
- Branch { true: Expression(26, Sub), false: Counter(3) } at (prev + 0, 33) to (start + 0, 34)
|
||||
true = (((((c1 - c7) - c6) - c5) - c4) - c3)
|
||||
false = c3
|
||||
- Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39)
|
||||
= (((((c1 - c7) - c6) - c5) - c4) - c3)
|
||||
- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 38) to (start + 0, 39)
|
||||
true = c8
|
||||
false = c2
|
||||
- Code(Counter(8)) at (prev + 0, 40) to (start + 2, 6)
|
||||
- Code(Expression(38, Add)) at (prev + 2, 6) to (start + 0, 7)
|
||||
= ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1))
|
||||
- Code(Expression(37, Add)) at (prev + 1, 1) to (start + 0, 2)
|
||||
= (c8 + ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1)))
|
||||
|
||||
Function name: condition_limit::good
|
||||
Raw bytes (180): 0x[01, 01, 20, 01, 05, 05, 19, 05, 19, 52, 15, 05, 19, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 1d, 6f, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 10, 01, 0c, 01, 03, 09, 28, 00, 06, 03, 08, 00, 22, 30, 05, 02, 01, 06, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 52, 19, 06, 05, 00, 00, 0d, 00, 0e, 52, 00, 12, 00, 13, 30, 4e, 15, 05, 04, 00, 00, 12, 00, 13, 4e, 00, 17, 00, 18, 30, 4a, 11, 04, 03, 00, 00, 17, 00, 18, 4a, 00, 1c, 00, 1d, 30, 46, 0d, 03, 02, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 1d, 09, 02, 00, 00, 00, 21, 00, 22, 1d, 00, 23, 02, 06, 6f, 02, 06, 00, 07, 6b, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 32
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 3 operands: lhs = Expression(20, Sub), rhs = Counter(5)
|
||||
- expression 4 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 5 operands: lhs = Expression(20, Sub), rhs = Counter(5)
|
||||
- expression 6 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 7 operands: lhs = Expression(19, Sub), rhs = Counter(4)
|
||||
- expression 8 operands: lhs = Expression(20, Sub), rhs = Counter(5)
|
||||
- expression 9 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 10 operands: lhs = Expression(19, Sub), rhs = Counter(4)
|
||||
- expression 11 operands: lhs = Expression(20, Sub), rhs = Counter(5)
|
||||
- expression 12 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(3)
|
||||
- expression 14 operands: lhs = Expression(19, Sub), rhs = Counter(4)
|
||||
- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(5)
|
||||
- expression 16 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(3)
|
||||
- expression 18 operands: lhs = Expression(19, Sub), rhs = Counter(4)
|
||||
- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(5)
|
||||
- expression 20 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 21 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub)
|
||||
- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(6)
|
||||
- expression 23 operands: lhs = Expression(30, Add), rhs = Counter(5)
|
||||
- expression 24 operands: lhs = Expression(31, Add), rhs = Counter(4)
|
||||
- expression 25 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 26 operands: lhs = Counter(7), rhs = Expression(27, Add)
|
||||
- expression 27 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub)
|
||||
- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(6)
|
||||
- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(5)
|
||||
- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(4)
|
||||
- expression 31 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
Number of file 0 mappings: 16
|
||||
- Code(Counter(0)) at (prev + 12, 1) to (start + 3, 9)
|
||||
- MCDCDecision { bitmap_idx: 0, conditions_num: 6 } at (prev + 3, 8) to (start + 0, 34)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 6, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCBranch { true: Expression(20, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = (c1 - c6)
|
||||
false = c6
|
||||
- Code(Expression(20, Sub)) at (prev + 0, 18) to (start + 0, 19)
|
||||
= (c1 - c6)
|
||||
- MCDCBranch { true: Expression(19, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = ((c1 - c6) - c5)
|
||||
false = c5
|
||||
- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 24)
|
||||
= ((c1 - c6) - c5)
|
||||
- MCDCBranch { true: Expression(18, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
|
||||
true = (((c1 - c6) - c5) - c4)
|
||||
false = c4
|
||||
- Code(Expression(18, Sub)) at (prev + 0, 28) to (start + 0, 29)
|
||||
= (((c1 - c6) - c5) - c4)
|
||||
- MCDCBranch { true: Expression(17, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29)
|
||||
true = ((((c1 - c6) - c5) - c4) - c3)
|
||||
false = c3
|
||||
- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34)
|
||||
= ((((c1 - c6) - c5) - c4) - c3)
|
||||
- MCDCBranch { true: Counter(7), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
|
||||
true = c7
|
||||
false = c2
|
||||
- Code(Counter(7)) at (prev + 0, 35) to (start + 2, 6)
|
||||
- Code(Expression(27, Add)) at (prev + 2, 6) to (start + 0, 7)
|
||||
= (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))
|
||||
- Code(Expression(26, Add)) at (prev + 1, 1) to (start + 0, 2)
|
||||
= (c7 + (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)))
|
||||
|
76
tests/coverage/mcdc/condition-limit.coverage
Normal file
76
tests/coverage/mcdc/condition-limit.coverage
Normal file
@ -0,0 +1,76 @@
|
||||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ min-llvm-version: 18
|
||||
LL| |//@ compile-flags: -Zcoverage-options=mcdc
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
LL| |
|
||||
LL| |// Check that MC/DC instrumentation can gracefully handle conditions that
|
||||
LL| |// exceed LLVM's limit of 6 conditions per decision.
|
||||
LL| |//
|
||||
LL| |// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.)
|
||||
LL| |
|
||||
LL| 1|fn good() {
|
||||
LL| 1| // With only 6 conditions, perform full MC/DC instrumentation.
|
||||
LL| 1| let [a, b, c, d, e, f] = <[bool; 6]>::default();
|
||||
LL| 1| if a && b && c && d && e && f {
|
||||
^0 ^0 ^0 ^0 ^0
|
||||
------------------
|
||||
| Branch (LL:8): [True: 0, False: 1]
|
||||
| Branch (LL:13): [True: 0, False: 0]
|
||||
| Branch (LL:18): [True: 0, False: 0]
|
||||
| Branch (LL:23): [True: 0, False: 0]
|
||||
| Branch (LL:28): [True: 0, False: 0]
|
||||
| Branch (LL:33): [True: 0, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:34)
|
||||
|
|
||||
| Number of Conditions: 6
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
| Condition C3 --> (LL:18)
|
||||
| Condition C4 --> (LL:23)
|
||||
| Condition C5 --> (LL:28)
|
||||
| Condition C6 --> (LL:33)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3, C4, C5, C6 Result
|
||||
| 1 { F, -, -, -, -, - = F }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: not covered
|
||||
| C3-Pair: not covered
|
||||
| C4-Pair: not covered
|
||||
| C5-Pair: not covered
|
||||
| C6-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 0.00%
|
||||
|
|
||||
------------------
|
||||
LL| 0| core::hint::black_box("hello");
|
||||
LL| 1| }
|
||||
LL| 1|}
|
||||
LL| |
|
||||
LL| 1|fn bad() {
|
||||
LL| 1| // With 7 conditions, fall back to branch instrumentation only.
|
||||
LL| 1| let [a, b, c, d, e, f, g] = <[bool; 7]>::default();
|
||||
LL| 1| if a && b && c && d && e && f && g {
|
||||
^0 ^0 ^0 ^0 ^0 ^0
|
||||
------------------
|
||||
| Branch (LL:8): [True: 0, False: 1]
|
||||
| Branch (LL:13): [True: 0, False: 0]
|
||||
| Branch (LL:18): [True: 0, False: 0]
|
||||
| Branch (LL:23): [True: 0, False: 0]
|
||||
| Branch (LL:28): [True: 0, False: 0]
|
||||
| Branch (LL:33): [True: 0, False: 0]
|
||||
| Branch (LL:38): [True: 0, False: 0]
|
||||
------------------
|
||||
LL| 0| core::hint::black_box("hello");
|
||||
LL| 1| }
|
||||
LL| 1|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | good();
|
||||
LL| | bad();
|
||||
LL| |}
|
||||
|
32
tests/coverage/mcdc/condition-limit.rs
Normal file
32
tests/coverage/mcdc/condition-limit.rs
Normal file
@ -0,0 +1,32 @@
|
||||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ min-llvm-version: 18
|
||||
//@ compile-flags: -Zcoverage-options=mcdc
|
||||
//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
|
||||
// Check that MC/DC instrumentation can gracefully handle conditions that
|
||||
// exceed LLVM's limit of 6 conditions per decision.
|
||||
//
|
||||
// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.)
|
||||
|
||||
fn good() {
|
||||
// With only 6 conditions, perform full MC/DC instrumentation.
|
||||
let [a, b, c, d, e, f] = <[bool; 6]>::default();
|
||||
if a && b && c && d && e && f {
|
||||
core::hint::black_box("hello");
|
||||
}
|
||||
}
|
||||
|
||||
fn bad() {
|
||||
// With 7 conditions, fall back to branch instrumentation only.
|
||||
let [a, b, c, d, e, f, g] = <[bool; 7]>::default();
|
||||
if a && b && c && d && e && f && g {
|
||||
core::hint::black_box("hello");
|
||||
}
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
good();
|
||||
bad();
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
Function name: <partial_eq::Version>::new
|
||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 06, 06]
|
||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 02, 06]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 1
|
||||
- Code(Counter(0)) at (prev + 12, 5) to (start + 6, 6)
|
||||
- Code(Counter(0)) at (prev + 12, 5) to (start + 2, 6)
|
||||
|
||||
Function name: partial_eq::main
|
||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 0a, 02]
|
||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 0a, 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 + 21, 1) to (start + 10, 2)
|
||||
- Code(Counter(0)) at (prev + 17, 1) to (start + 10, 2)
|
||||
|
||||
|
@ -10,11 +10,7 @@
|
||||
LL| |
|
||||
LL| |impl Version {
|
||||
LL| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self {
|
||||
LL| 2| Self {
|
||||
LL| 2| major,
|
||||
LL| 2| minor,
|
||||
LL| 2| patch,
|
||||
LL| 2| }
|
||||
LL| 2| Self { major, minor, patch }
|
||||
LL| 2| }
|
||||
LL| |}
|
||||
LL| |
|
||||
@ -26,7 +22,7 @@
|
||||
LL| 1| "{:?} < {:?} = {}",
|
||||
LL| 1| version_3_2_1,
|
||||
LL| 1| version_3_3_0,
|
||||
LL| 1| version_3_2_1 < version_3_3_0
|
||||
LL| 1| version_3_2_1 < version_3_3_0, //
|
||||
LL| 1| );
|
||||
LL| 1|}
|
||||
LL| |
|
||||
|
@ -10,11 +10,7 @@ pub struct Version {
|
||||
|
||||
impl Version {
|
||||
pub fn new(major: usize, minor: usize, patch: usize) -> Self {
|
||||
Self {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
}
|
||||
Self { major, minor, patch }
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +22,7 @@ fn main() {
|
||||
"{:?} < {:?} = {}",
|
||||
version_3_2_1,
|
||||
version_3_3_0,
|
||||
version_3_2_1 < version_3_3_0
|
||||
version_3_2_1 < version_3_3_0, //
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -25,26 +25,26 @@ Number of file 0 mappings: 4
|
||||
- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
|
||||
|
||||
Function name: try_error_result::call
|
||||
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02]
|
||||
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 1
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 4
|
||||
- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20)
|
||||
- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 20)
|
||||
- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16)
|
||||
- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
|
||||
= (c0 - c1)
|
||||
- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
|
||||
|
||||
Function name: try_error_result::main
|
||||
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02]
|
||||
Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 1
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 4
|
||||
- Code(Counter(0)) at (prev + 115, 1) to (start + 2, 12)
|
||||
- Code(Counter(0)) at (prev + 113, 1) to (start + 2, 12)
|
||||
- Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6)
|
||||
- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11)
|
||||
= (c0 - c1)
|
||||
@ -81,7 +81,7 @@ Number of file 0 mappings: 11
|
||||
= (((c4 + Zero) + Zero) + c3)
|
||||
|
||||
Function name: try_error_result::test2
|
||||
Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3e, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02]
|
||||
Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 36
|
||||
@ -122,7 +122,7 @@ Number of expressions: 36
|
||||
- expression 34 operands: lhs = Expression(35, Add), rhs = Zero
|
||||
- expression 35 operands: lhs = Counter(6), rhs = Zero
|
||||
Number of file 0 mappings: 40
|
||||
- Code(Counter(0)) at (prev + 62, 1) to (start + 3, 23)
|
||||
- Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23)
|
||||
- Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14)
|
||||
= (c0 + (Zero + c2))
|
||||
- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 4, 26)
|
||||
|
@ -1,4 +1,5 @@
|
||||
LL| |#![allow(unused_assignments)]
|
||||
LL| |#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
LL| |//@ failure-status: 1
|
||||
LL| |
|
||||
LL| 6|fn call(return_error: bool) -> Result<(), ()> {
|
||||
@ -9,7 +10,6 @@
|
||||
LL| | }
|
||||
LL| 6|}
|
||||
LL| |
|
||||
LL| |#[rustfmt::skip]
|
||||
LL| 1|fn test1() -> Result<(), ()> {
|
||||
LL| 1| let mut
|
||||
LL| 1| countdown = 10
|
||||
@ -59,7 +59,6 @@
|
||||
LL| 17| }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[rustfmt::skip]
|
||||
LL| 1|fn test2() -> Result<(), ()> {
|
||||
LL| 1| let thing1 = Thing1{};
|
||||
LL| 1| let mut
|
||||
@ -117,7 +116,6 @@
|
||||
LL| 0| Ok(())
|
||||
LL| 1|}
|
||||
LL| |
|
||||
LL| |#[rustfmt::skip]
|
||||
LL| 1|fn main() -> Result<(), ()> {
|
||||
LL| 1| test1().expect_err("test1 should fail");
|
||||
LL| 1| test2()
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![allow(unused_assignments)]
|
||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
//@ failure-status: 1
|
||||
|
||||
fn call(return_error: bool) -> Result<(), ()> {
|
||||
@ -9,7 +10,6 @@ fn call(return_error: bool) -> Result<(), ()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn test1() -> Result<(), ()> {
|
||||
let mut
|
||||
countdown = 10
|
||||
@ -58,7 +58,6 @@ impl Thing2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn test2() -> Result<(), ()> {
|
||||
let thing1 = Thing1{};
|
||||
let mut
|
||||
@ -111,7 +110,6 @@ fn test2() -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() -> Result<(), ()> {
|
||||
test1().expect_err("test1 should fail");
|
||||
test2()
|
||||
|
@ -19,69 +19,69 @@ $DIR/auxiliary/used_crate.rs:
|
||||
LL| 1|}
|
||||
LL| |
|
||||
LL| 2|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
LL| 2| println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
LL| 2|}
|
||||
------------------
|
||||
| Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_>
|
||||
------------------
|
||||
| used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
|
||||
| LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
| used_crate::used_only_from_bin_crate_generic_function::<&str>:
|
||||
| LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
LL| |// Expect for above function: `Unexecuted instantiation` (see below)
|
||||
LL| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
LL| 2|}
|
||||
------------------
|
||||
| used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
|
||||
| LL| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
| used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
||||
| LL| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
LL| |
|
||||
LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
LL| 2|}
|
||||
------------------
|
||||
| used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||
| LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
| used_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
||||
| LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
LL| |
|
||||
LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
LL| 2|}
|
||||
------------------
|
||||
| used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||
| LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
| used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||
| LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
LL| |
|
||||
LL| 0|pub fn unused_generic_function<T: Debug>(arg: T) {
|
||||
LL| 0| println!("unused_generic_function with {:?}", arg);
|
||||
LL| 0| println!("unused_generic_function with {arg:?}");
|
||||
LL| 0|}
|
||||
LL| |
|
||||
LL| 0|pub fn unused_function() {
|
||||
|
@ -34,74 +34,74 @@ $DIR/auxiliary/used_inline_crate.rs:
|
||||
LL| |
|
||||
LL| |#[inline(always)]
|
||||
LL| 2|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
LL| 2| println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
LL| 2|}
|
||||
------------------
|
||||
| Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_>
|
||||
------------------
|
||||
| used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
|
||||
| LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
| used_inline_crate::used_only_from_bin_crate_generic_function::<&str>:
|
||||
| LL| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
LL| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`)
|
||||
LL| |
|
||||
LL| |#[inline(always)]
|
||||
LL| 4|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
LL| 4| println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
LL| 4|}
|
||||
------------------
|
||||
| used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>:
|
||||
| LL| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 2|}
|
||||
------------------
|
||||
| used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
||||
| LL| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 2|}
|
||||
------------------
|
||||
LL| |
|
||||
LL| |#[inline(always)]
|
||||
LL| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
LL| 3|}
|
||||
------------------
|
||||
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||
| LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 2|}
|
||||
------------------
|
||||
| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
|
||||
| LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
LL| |
|
||||
LL| |#[inline(always)]
|
||||
LL| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
LL| 3|}
|
||||
------------------
|
||||
| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||
| LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 1|}
|
||||
------------------
|
||||
| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>:
|
||||
| LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) {
|
||||
| LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg);
|
||||
| LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}");
|
||||
| LL| 2|}
|
||||
------------------
|
||||
LL| |
|
||||
LL| |#[inline(always)]
|
||||
LL| 0|pub fn unused_generic_function<T: Debug>(arg: T) {
|
||||
LL| 0| println!("unused_generic_function with {:?}", arg);
|
||||
LL| 0| println!("unused_generic_function with {arg:?}");
|
||||
LL| 0|}
|
||||
LL| |
|
||||
LL| |#[inline(always)]
|
||||
|
@ -1,5 +1,5 @@
|
||||
Function name: yield::main
|
||||
Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 22, 15, 0d, 11, 11, 15, 22, 15, 0d, 11, 22, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 06, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 22, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 13, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 07, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02]
|
||||
Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 22, 15, 0d, 11, 11, 15, 22, 15, 0d, 11, 22, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 22, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 13, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 08, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 11
|
||||
@ -16,7 +16,7 @@ Number of expressions: 11
|
||||
- expression 10 operands: lhs = Counter(9), rhs = Counter(10)
|
||||
Number of file 0 mappings: 16
|
||||
- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22)
|
||||
- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 46)
|
||||
- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46)
|
||||
- Code(Counter(3)) at (prev + 1, 39) to (start + 0, 41)
|
||||
- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 52)
|
||||
= (c1 + Zero)
|
||||
@ -29,7 +29,7 @@ Number of file 0 mappings: 16
|
||||
= (c4 + c5)
|
||||
- Code(Expression(7, Sub)) at (prev + 3, 9) to (start + 0, 22)
|
||||
= ((c3 - c4) - c5)
|
||||
- Code(Expression(7, Sub)) at (prev + 7, 11) to (start + 0, 46)
|
||||
- Code(Expression(7, Sub)) at (prev + 8, 11) to (start + 0, 46)
|
||||
= ((c3 - c4) - c5)
|
||||
- Code(Counter(8)) at (prev + 1, 39) to (start + 0, 41)
|
||||
- Code(Expression(9, Add)) at (prev + 1, 14) to (start + 0, 52)
|
||||
@ -41,21 +41,21 @@ Number of file 0 mappings: 16
|
||||
- Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2)
|
||||
|
||||
Function name: yield::main::{closure#0}
|
||||
Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 29, 01, 10, 05, 02, 10, 01, 06]
|
||||
Raw bytes (14): 0x[01, 01, 00, 02, 01, 09, 08, 01, 10, 05, 02, 10, 01, 06]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 2
|
||||
- Code(Counter(0)) at (prev + 8, 41) to (start + 1, 16)
|
||||
- Code(Counter(0)) at (prev + 9, 8) to (start + 1, 16)
|
||||
- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6)
|
||||
|
||||
Function name: yield::main::{closure#1}
|
||||
Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 29, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06]
|
||||
Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 08, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 4
|
||||
- Code(Counter(0)) at (prev + 22, 41) to (start + 1, 16)
|
||||
- Code(Counter(0)) at (prev + 24, 8) to (start + 1, 16)
|
||||
- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16)
|
||||
- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16)
|
||||
- Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6)
|
||||
|
@ -5,7 +5,8 @@
|
||||
LL| |use std::pin::Pin;
|
||||
LL| |
|
||||
LL| 1|fn main() {
|
||||
LL| 1| let mut coroutine = #[coroutine] || {
|
||||
LL| 1| let mut coroutine = #[coroutine]
|
||||
LL| 1| || {
|
||||
LL| 1| yield 1;
|
||||
LL| 1| return "foo";
|
||||
LL| 1| };
|
||||
@ -19,7 +20,8 @@
|
||||
LL| 0| _ => panic!("unexpected value from resume"),
|
||||
LL| | }
|
||||
LL| |
|
||||
LL| 1| let mut coroutine = #[coroutine] || {
|
||||
LL| 1| let mut coroutine = #[coroutine]
|
||||
LL| 1| || {
|
||||
LL| 1| yield 1;
|
||||
LL| 1| yield 2;
|
||||
LL| 0| yield 3;
|
||||
|
@ -5,7 +5,8 @@ use std::ops::{Coroutine, CoroutineState};
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
let mut coroutine = #[coroutine] || {
|
||||
let mut coroutine = #[coroutine]
|
||||
|| {
|
||||
yield 1;
|
||||
return "foo";
|
||||
};
|
||||
@ -19,7 +20,8 @@ fn main() {
|
||||
_ => panic!("unexpected value from resume"),
|
||||
}
|
||||
|
||||
let mut coroutine = #[coroutine] || {
|
||||
let mut coroutine = #[coroutine]
|
||||
|| {
|
||||
yield 1;
|
||||
yield 2;
|
||||
yield 3;
|
||||
|
@ -4,8 +4,6 @@
|
||||
//@ needs-rust-lld
|
||||
//@ only-x86_64-unknown-linux-gnu
|
||||
|
||||
extern crate run_make_support;
|
||||
|
||||
use run_make_support::regex::Regex;
|
||||
use run_make_support::rustc;
|
||||
use std::process::Output;
|
||||
|
25
tests/ui/abi/fixed_x18.rs
Normal file
25
tests/ui/abi/fixed_x18.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// This tests that -Zfixed-x18 causes a compilation failure on targets other than aarch64.
|
||||
// Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs.
|
||||
//
|
||||
//@ revisions: x64 i686 arm riscv32 riscv64
|
||||
//@ error-pattern: the `-Zfixed-x18` flag is not supported
|
||||
//@ dont-check-compiler-stderr
|
||||
//
|
||||
//@ compile-flags: -Zfixed-x18
|
||||
//@ [x64] needs-llvm-components: x86
|
||||
//@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
|
||||
//@ [i686] needs-llvm-components: x86
|
||||
//@ [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib
|
||||
//@ [arm] needs-llvm-components: arm
|
||||
//@ [arm] compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib
|
||||
//@ [riscv32] needs-llvm-components: riscv
|
||||
//@ [riscv32] compile-flags: --target=riscv32i-unknown-none-elf --crate-type=rlib
|
||||
//@ [riscv64] needs-llvm-components: riscv
|
||||
//@ [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf --crate-type=rlib
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
6
tests/ui/inline-const/referencing_local_variables.rs
Normal file
6
tests/ui/inline-const/referencing_local_variables.rs
Normal file
@ -0,0 +1,6 @@
|
||||
const fn test_me<T>(a: usize) -> usize {
|
||||
const { a }
|
||||
//~^ ERROR: attempt to use a non-constant value in a constant
|
||||
}
|
||||
|
||||
fn main() {}
|
11
tests/ui/inline-const/referencing_local_variables.stderr
Normal file
11
tests/ui/inline-const/referencing_local_variables.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0435]: attempt to use a non-constant value in a constant
|
||||
--> $DIR/referencing_local_variables.rs:2:13
|
||||
|
|
||||
LL | const fn test_me<T>(a: usize) -> usize {
|
||||
| - this would need to be a `const`
|
||||
LL | const { a }
|
||||
| ^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0435`.
|
@ -0,0 +1,8 @@
|
||||
warning: Conditions number of the decision (7) exceeds limit (6). MCDC analysis will not count this expression.
|
||||
--> $DIR/mcdc-condition-limit.rs:29:8
|
||||
|
|
||||
LL | if a && b && c && d && e && f && g {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
32
tests/ui/instrument-coverage/mcdc-condition-limit.rs
Normal file
32
tests/ui/instrument-coverage/mcdc-condition-limit.rs
Normal file
@ -0,0 +1,32 @@
|
||||
//@ edition: 2021
|
||||
//@ min-llvm-version: 18
|
||||
//@ revisions: good bad
|
||||
//@ check-pass
|
||||
//@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime
|
||||
|
||||
// Check that we emit some kind of diagnostic when MC/DC instrumentation sees
|
||||
// code that exceeds the limit of 6 conditions per decision, and falls back
|
||||
// to only instrumenting that code for branch coverage.
|
||||
//
|
||||
// See also `tests/coverage/mcdc/condition-limit.rs`, which tests the actual
|
||||
// effect on instrumentation.
|
||||
//
|
||||
// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.)
|
||||
|
||||
#[cfg(good)]
|
||||
fn main() {
|
||||
// 6 conditions is OK, so no diagnostic.
|
||||
let [a, b, c, d, e, f] = <[bool; 6]>::default();
|
||||
if a && b && c && d && e && f {
|
||||
core::hint::black_box("hello");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(bad)]
|
||||
fn main() {
|
||||
// 7 conditions is too many, so issue a diagnostic.
|
||||
let [a, b, c, d, e, f, g] = <[bool; 7]>::default();
|
||||
if a && b && c && d && e && f && g { //[bad]~ WARNING Conditions number of the decision
|
||||
core::hint::black_box("hello");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user