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:
bors 2024-05-29 20:11:09 +00:00
commit debd22da66
45 changed files with 897 additions and 534 deletions

View File

@ -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}

View File

@ -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,
}

View File

@ -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,

View File

@ -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)));

View File

@ -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 {

View File

@ -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);

View File

@ -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)"),

View File

@ -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

View 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

View File

@ -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());

View 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(())
}
}

View File

@ -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);
}

View 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{{.*}} }
}

View File

@ -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() {

View File

@ -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)]

View File

@ -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)

View File

@ -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| };

View File

@ -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";
};

View File

@ -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| | }

View File

@ -13,7 +13,7 @@ fn main() {
#[inline]
fn live<const B: bool>() -> u32 {
if B {
dead()
dead() //
} else {
0
}

View File

@ -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();

View File

@ -50,7 +50,7 @@ fn main() {
}
let mut val = InStruct {
in_struct_field: 101,
in_struct_field: 101, //
};
val.default_trait_func();

View File

@ -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]

View File

@ -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)]

View File

@ -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)]

View 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)))

View 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| |}

View 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();
}

View File

@ -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)

View File

@ -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| |

View File

@ -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, //
);
}

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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() {

View File

@ -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)]

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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
View 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 {}

View 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() {}

View 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`.

View File

@ -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

View 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");
}
}