Merge from rustc
This commit is contained in:
commit
e898da11d2
495 changed files with 5342 additions and 1962 deletions
|
|
@ -160,10 +160,10 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||
"needs-xray",
|
||||
"no-auto-check-cfg",
|
||||
"no-prefer-dynamic",
|
||||
"normalize-stderr",
|
||||
"normalize-stderr-32bit",
|
||||
"normalize-stderr-64bit",
|
||||
"normalize-stderr-test",
|
||||
"normalize-stdout-test",
|
||||
"normalize-stdout",
|
||||
"only-16bit",
|
||||
"only-32bit",
|
||||
"only-64bit",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use tracing::*;
|
|||
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
|
||||
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
|
||||
use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
|
||||
use crate::header::cfg::{MatchOutcome, parse_cfg_name_directive};
|
||||
use crate::header::needs::CachedNeedsConditions;
|
||||
use crate::util::static_regex;
|
||||
|
||||
|
|
@ -472,11 +471,24 @@ impl TestProps {
|
|||
|
||||
config.set_name_directive(ln, IGNORE_PASS, &mut self.ignore_pass);
|
||||
|
||||
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") {
|
||||
self.normalize_stdout.push(rule);
|
||||
}
|
||||
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") {
|
||||
self.normalize_stderr.push(rule);
|
||||
if let Some(NormalizeRule { kind, regex, replacement }) =
|
||||
config.parse_custom_normalization(ln)
|
||||
{
|
||||
let rule_tuple = (regex, replacement);
|
||||
match kind {
|
||||
NormalizeKind::Stdout => self.normalize_stdout.push(rule_tuple),
|
||||
NormalizeKind::Stderr => self.normalize_stderr.push(rule_tuple),
|
||||
NormalizeKind::Stderr32bit => {
|
||||
if config.target_cfg().pointer_width == 32 {
|
||||
self.normalize_stderr.push(rule_tuple);
|
||||
}
|
||||
}
|
||||
NormalizeKind::Stderr64bit => {
|
||||
if config.target_cfg().pointer_width == 64 {
|
||||
self.normalize_stderr.push(rule_tuple);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(code) = config
|
||||
|
|
@ -966,20 +978,26 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_custom_normalization(&self, line: &str, prefix: &str) -> Option<(String, String)> {
|
||||
let parsed = parse_cfg_name_directive(self, line, prefix);
|
||||
if parsed.outcome != MatchOutcome::Match {
|
||||
return None;
|
||||
}
|
||||
let name = parsed.name.expect("successful match always has a name");
|
||||
fn parse_custom_normalization(&self, raw_directive: &str) -> Option<NormalizeRule> {
|
||||
// FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine`
|
||||
// instead of doing it here.
|
||||
let (directive_name, raw_value) = raw_directive.split_once(':')?;
|
||||
|
||||
let Some((regex, replacement)) = parse_normalize_rule(line) else {
|
||||
let kind = match directive_name {
|
||||
"normalize-stdout" => NormalizeKind::Stdout,
|
||||
"normalize-stderr" => NormalizeKind::Stderr,
|
||||
"normalize-stderr-32bit" => NormalizeKind::Stderr32bit,
|
||||
"normalize-stderr-64bit" => NormalizeKind::Stderr64bit,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let Some((regex, replacement)) = parse_normalize_rule(raw_value) else {
|
||||
panic!(
|
||||
"couldn't parse custom normalization rule: `{line}`\n\
|
||||
help: expected syntax is: `{prefix}-{name}: \"REGEX\" -> \"REPLACEMENT\"`"
|
||||
"couldn't parse custom normalization rule: `{raw_directive}`\n\
|
||||
help: expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`"
|
||||
);
|
||||
};
|
||||
Some((regex, replacement))
|
||||
Some(NormalizeRule { kind, regex, replacement })
|
||||
}
|
||||
|
||||
fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
|
||||
|
|
@ -1105,27 +1123,42 @@ fn expand_variables(mut value: String, config: &Config) -> String {
|
|||
value
|
||||
}
|
||||
|
||||
struct NormalizeRule {
|
||||
kind: NormalizeKind,
|
||||
regex: String,
|
||||
replacement: String,
|
||||
}
|
||||
|
||||
enum NormalizeKind {
|
||||
Stdout,
|
||||
Stderr,
|
||||
Stderr32bit,
|
||||
Stderr64bit,
|
||||
}
|
||||
|
||||
/// Parses the regex and replacement values of a `//@ normalize-*` header,
|
||||
/// in the format:
|
||||
/// ```text
|
||||
/// normalize-*: "REGEX" -> "REPLACEMENT"
|
||||
/// "REGEX" -> "REPLACEMENT"
|
||||
/// ```
|
||||
fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
|
||||
fn parse_normalize_rule(raw_value: &str) -> Option<(String, String)> {
|
||||
// FIXME: Support escaped double-quotes in strings.
|
||||
let captures = static_regex!(
|
||||
r#"(?x) # (verbose mode regex)
|
||||
^
|
||||
[^:\s]+:\s* # (header name followed by colon)
|
||||
\s* # (leading whitespace)
|
||||
"(?<regex>[^"]*)" # "REGEX"
|
||||
\s+->\s+ # ->
|
||||
"(?<replacement>[^"]*)" # "REPLACEMENT"
|
||||
$
|
||||
"#
|
||||
)
|
||||
.captures(header)?;
|
||||
.captures(raw_value)?;
|
||||
let regex = captures["regex"].to_owned();
|
||||
let replacement = captures["replacement"].to_owned();
|
||||
// FIXME: Support escaped new-line in strings.
|
||||
// A `\n` sequence in the replacement becomes an actual newline.
|
||||
// FIXME: Do unescaping in a less ad-hoc way, and perhaps support escaped
|
||||
// backslashes and double-quotes.
|
||||
let replacement = replacement.replace("\\n", "\n");
|
||||
Some((regex, replacement))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
|
|||
}
|
||||
|
||||
/// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
|
||||
/// or `normalize-stderr-32bit`.
|
||||
pub(super) fn parse_cfg_name_directive<'a>(
|
||||
/// or `only-windows`.
|
||||
fn parse_cfg_name_directive<'a>(
|
||||
config: &Config,
|
||||
line: &'a str,
|
||||
prefix: &str,
|
||||
|
|
|
|||
|
|
@ -35,11 +35,14 @@ fn make_test_description<R: Read>(
|
|||
|
||||
#[test]
|
||||
fn test_parse_normalize_rule() {
|
||||
let good_data = &[(
|
||||
r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)""#,
|
||||
"something (32 bits)",
|
||||
"something ($WORD bits)",
|
||||
)];
|
||||
let good_data = &[
|
||||
(
|
||||
r#""something (32 bits)" -> "something ($WORD bits)""#,
|
||||
"something (32 bits)",
|
||||
"something ($WORD bits)",
|
||||
),
|
||||
(r#" " with whitespace" -> " replacement""#, " with whitespace", " replacement"),
|
||||
];
|
||||
|
||||
for &(input, expected_regex, expected_replacement) in good_data {
|
||||
let parsed = parse_normalize_rule(input);
|
||||
|
|
@ -49,15 +52,15 @@ fn test_parse_normalize_rule() {
|
|||
}
|
||||
|
||||
let bad_data = &[
|
||||
r#"normalize-stderr-32bit "something (32 bits)" -> "something ($WORD bits)""#,
|
||||
r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)"#,
|
||||
r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)"#,
|
||||
r#"normalize-stderr-32bit: "something (32 bits) -> something ($WORD bits)"#,
|
||||
r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"#,
|
||||
r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"."#,
|
||||
r#"something (11 bits) -> something ($WORD bits)"#,
|
||||
r#"something (12 bits) -> something ($WORD bits)"#,
|
||||
r#""something (13 bits) -> something ($WORD bits)"#,
|
||||
r#""something (14 bits)" -> "something ($WORD bits)"#,
|
||||
r#""something (15 bits)" -> "something ($WORD bits)"."#,
|
||||
];
|
||||
|
||||
for &input in bad_data {
|
||||
println!("- {input:?}");
|
||||
let parsed = parse_normalize_rule(input);
|
||||
assert_eq!(parsed, None);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
)
|
||||
.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
|
||||
.optflag("", "only-modified", "only run tests that result been modified")
|
||||
// FIXME: Temporarily retained so we can point users to `--no-capture`
|
||||
.optflag("", "nocapture", "")
|
||||
.optflag("", "no-capture", "don't capture stdout/stderr of tests")
|
||||
.optflag("", "profiler-runtime", "is the profiler runtime enabled for this target")
|
||||
.optflag("h", "help", "show this message")
|
||||
.reqopt("", "channel", "current Rust channel", "CHANNEL")
|
||||
|
|
@ -288,6 +290,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
);
|
||||
})
|
||||
});
|
||||
if matches.opt_present("nocapture") {
|
||||
panic!("`--nocapture` is deprecated; please use `--no-capture`");
|
||||
}
|
||||
|
||||
Config {
|
||||
bless: matches.opt_present("bless"),
|
||||
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
|
||||
|
|
@ -385,7 +391,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
target_cfgs: OnceLock::new(),
|
||||
builtin_cfg_names: OnceLock::new(),
|
||||
|
||||
nocapture: matches.opt_present("nocapture"),
|
||||
nocapture: matches.opt_present("no-capture"),
|
||||
|
||||
git_repository: matches.opt_str("git-repository").unwrap(),
|
||||
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ fn remove_and_create_dir_all(path: &Path) {
|
|||
fs::create_dir_all(path).unwrap();
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct TestCx<'test> {
|
||||
config: &'test Config,
|
||||
props: &'test TestProps,
|
||||
|
|
@ -2318,32 +2318,47 @@ impl<'test> TestCx<'test> {
|
|||
match output_kind {
|
||||
TestOutput::Compile => {
|
||||
if !self.props.dont_check_compiler_stdout {
|
||||
errors += self.compare_output(
|
||||
if self
|
||||
.compare_output(
|
||||
stdout_kind,
|
||||
&normalized_stdout,
|
||||
&proc_res.stdout,
|
||||
&expected_stdout,
|
||||
)
|
||||
.should_error()
|
||||
{
|
||||
errors += 1;
|
||||
}
|
||||
}
|
||||
if !self.props.dont_check_compiler_stderr {
|
||||
if self
|
||||
.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr)
|
||||
.should_error()
|
||||
{
|
||||
errors += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
TestOutput::Run => {
|
||||
if self
|
||||
.compare_output(
|
||||
stdout_kind,
|
||||
&normalized_stdout,
|
||||
&proc_res.stdout,
|
||||
&expected_stdout,
|
||||
);
|
||||
)
|
||||
.should_error()
|
||||
{
|
||||
errors += 1;
|
||||
}
|
||||
if !self.props.dont_check_compiler_stderr {
|
||||
errors += self.compare_output(
|
||||
stderr_kind,
|
||||
&normalized_stderr,
|
||||
&stderr,
|
||||
&expected_stderr,
|
||||
);
|
||||
|
||||
if self
|
||||
.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr)
|
||||
.should_error()
|
||||
{
|
||||
errors += 1;
|
||||
}
|
||||
}
|
||||
TestOutput::Run => {
|
||||
errors += self.compare_output(
|
||||
stdout_kind,
|
||||
&normalized_stdout,
|
||||
&proc_res.stdout,
|
||||
&expected_stdout,
|
||||
);
|
||||
errors +=
|
||||
self.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr);
|
||||
}
|
||||
}
|
||||
errors
|
||||
}
|
||||
|
|
@ -2576,7 +2591,14 @@ impl<'test> TestCx<'test> {
|
|||
actual: &str,
|
||||
actual_unnormalized: &str,
|
||||
expected: &str,
|
||||
) -> usize {
|
||||
) -> CompareOutcome {
|
||||
let expected_path =
|
||||
expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
|
||||
|
||||
if self.config.bless && actual.is_empty() && expected_path.exists() {
|
||||
self.delete_file(&expected_path);
|
||||
}
|
||||
|
||||
let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
|
||||
// FIXME: We ignore the first line of SVG files
|
||||
// because the width parameter is non-deterministic.
|
||||
|
|
@ -2584,7 +2606,7 @@ impl<'test> TestCx<'test> {
|
|||
_ => expected != actual,
|
||||
};
|
||||
if !are_different {
|
||||
return 0;
|
||||
return CompareOutcome::Same;
|
||||
}
|
||||
|
||||
// Wrapper tools set by `runner` might provide extra output on failure,
|
||||
|
|
@ -2600,7 +2622,7 @@ impl<'test> TestCx<'test> {
|
|||
used.retain(|line| actual_lines.contains(line));
|
||||
// check if `expected` contains a subset of the lines of `actual`
|
||||
if used.len() == expected_lines.len() && (expected.is_empty() == actual.is_empty()) {
|
||||
return 0;
|
||||
return CompareOutcome::Same;
|
||||
}
|
||||
if expected_lines.is_empty() {
|
||||
// if we have no lines to check, force a full overwite
|
||||
|
|
@ -2626,9 +2648,6 @@ impl<'test> TestCx<'test> {
|
|||
}
|
||||
println!("Saved the actual {stream} to {actual_path:?}");
|
||||
|
||||
let expected_path =
|
||||
expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
|
||||
|
||||
if !self.config.bless {
|
||||
if expected.is_empty() {
|
||||
println!("normalized {}:\n{}\n", stream, actual);
|
||||
|
|
@ -2651,15 +2670,17 @@ impl<'test> TestCx<'test> {
|
|||
self.delete_file(&old);
|
||||
}
|
||||
|
||||
if let Err(err) = fs::write(&expected_path, &actual) {
|
||||
self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
|
||||
if !actual.is_empty() {
|
||||
if let Err(err) = fs::write(&expected_path, &actual) {
|
||||
self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
|
||||
}
|
||||
println!("Blessing the {stream} of {test_name} in {expected_path:?}");
|
||||
}
|
||||
println!("Blessing the {stream} of {test_name} in {expected_path:?}");
|
||||
}
|
||||
|
||||
println!("\nThe actual {0} differed from the expected {0}.", stream);
|
||||
|
||||
if self.config.bless { 0 } else { 1 }
|
||||
if self.config.bless { CompareOutcome::Blessed } else { CompareOutcome::Differed }
|
||||
}
|
||||
|
||||
/// Returns whether to show the full stderr/stdout.
|
||||
|
|
@ -2885,3 +2906,21 @@ enum AuxType {
|
|||
Dylib,
|
||||
ProcMacro,
|
||||
}
|
||||
|
||||
/// Outcome of comparing a stream to a blessed file,
|
||||
/// e.g. `.stderr` and `.fixed`.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum CompareOutcome {
|
||||
/// Expected and actual outputs are the same
|
||||
Same,
|
||||
/// Outputs differed but were blessed
|
||||
Blessed,
|
||||
/// Outputs differed and an error should be emitted
|
||||
Differed,
|
||||
}
|
||||
|
||||
impl CompareOutcome {
|
||||
fn should_error(&self) -> bool {
|
||||
matches!(self, CompareOutcome::Differed)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,16 +39,16 @@ impl<'test> TestCx<'test> {
|
|||
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(
|
||||
let coverage_dump_compare_outcome = self.compare_output(
|
||||
kind,
|
||||
&actual_coverage_dump,
|
||||
&proc_res.stdout,
|
||||
&expected_coverage_dump,
|
||||
);
|
||||
|
||||
if coverage_dump_errors > 0 {
|
||||
if coverage_dump_compare_outcome.should_error() {
|
||||
self.fatal_proc_rec(
|
||||
&format!("{coverage_dump_errors} errors occurred comparing coverage output."),
|
||||
&format!("an error occurred comparing coverage output."),
|
||||
&proc_res,
|
||||
);
|
||||
}
|
||||
|
|
@ -139,16 +139,16 @@ impl<'test> TestCx<'test> {
|
|||
self.fatal_proc_rec(&err, &proc_res);
|
||||
});
|
||||
|
||||
let coverage_errors = self.compare_output(
|
||||
let coverage_dump_compare_outcome = self.compare_output(
|
||||
kind,
|
||||
&normalized_actual_coverage,
|
||||
&proc_res.stdout,
|
||||
&expected_coverage,
|
||||
);
|
||||
|
||||
if coverage_errors > 0 {
|
||||
if coverage_dump_compare_outcome.should_error() {
|
||||
self.fatal_proc_rec(
|
||||
&format!("{} errors occurred comparing coverage output.", coverage_errors),
|
||||
&format!("an error occurred comparing coverage output."),
|
||||
&proc_res,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,9 @@ pub(super) struct DebuggerCommands {
|
|||
}
|
||||
|
||||
impl DebuggerCommands {
|
||||
pub fn parse_from(
|
||||
file: &Path,
|
||||
config: &Config,
|
||||
debugger_prefixes: &[&str],
|
||||
) -> Result<Self, String> {
|
||||
let directives = debugger_prefixes
|
||||
.iter()
|
||||
.map(|prefix| (format!("{prefix}-command"), format!("{prefix}-check")))
|
||||
.collect::<Vec<_>>();
|
||||
pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result<Self, String> {
|
||||
let command_directive = format!("{debugger_prefix}-command");
|
||||
let check_directive = format!("{debugger_prefix}-check");
|
||||
|
||||
let mut breakpoint_lines = vec![];
|
||||
let mut commands = vec![];
|
||||
|
|
@ -48,14 +42,11 @@ impl DebuggerCommands {
|
|||
continue;
|
||||
};
|
||||
|
||||
for &(ref command_directive, ref check_directive) in &directives {
|
||||
config
|
||||
.parse_name_value_directive(&line, command_directive)
|
||||
.map(|cmd| commands.push(cmd));
|
||||
|
||||
config
|
||||
.parse_name_value_directive(&line, check_directive)
|
||||
.map(|cmd| check_lines.push((line_no, cmd)));
|
||||
if let Some(command) = config.parse_name_value_directive(&line, &command_directive) {
|
||||
commands.push(command);
|
||||
}
|
||||
if let Some(pattern) = config.parse_name_value_directive(&line, &check_directive) {
|
||||
check_lines.push((line_no, pattern));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,14 +59,8 @@ impl TestCx<'_> {
|
|||
return;
|
||||
}
|
||||
|
||||
let prefixes = {
|
||||
static PREFIXES: &[&str] = &["cdb", "cdbg"];
|
||||
// No "native rust support" variation for CDB yet.
|
||||
PREFIXES
|
||||
};
|
||||
|
||||
// Parse debugger commands etc from test files
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes)
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "cdb")
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
|
||||
|
|
@ -137,7 +131,7 @@ impl TestCx<'_> {
|
|||
}
|
||||
|
||||
fn run_debuginfo_gdb_test_no_opt(&self) {
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"])
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "gdb")
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let mut cmds = dbg_cmds.commands.join("\n");
|
||||
|
||||
|
|
@ -403,7 +397,7 @@ impl TestCx<'_> {
|
|||
}
|
||||
|
||||
// Parse debugger commands etc from test files
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"])
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "lldb")
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
|
||||
// Write debugger script:
|
||||
|
|
|
|||
|
|
@ -100,7 +100,12 @@ impl TestCx<'_> {
|
|||
)
|
||||
});
|
||||
|
||||
errors += self.compare_output("fixed", &fixed_code, &fixed_code, &expected_fixed);
|
||||
if self
|
||||
.compare_output("fixed", &fixed_code, &fixed_code, &expected_fixed)
|
||||
.should_error()
|
||||
{
|
||||
errors += 1;
|
||||
}
|
||||
} else if !expected_fixed.is_empty() {
|
||||
panic!(
|
||||
"the `//@ run-rustfix` directive wasn't found but a `*.fixed` \
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
//!
|
||||
//! Currently uses a combination of HTML parsing to
|
||||
//! extract the `href` and `id` attributes,
|
||||
//! and regex search on the orignal markdown to handle intra-doc links.
|
||||
//! and regex search on the original markdown to handle intra-doc links.
|
||||
//!
|
||||
//! These values are then translated to file URLs if possible and then the
|
||||
//! destination is asserted to exist.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::intrinsics::typed_swap;
|
||||
use std::intrinsics::typed_swap_nonoverlapping;
|
||||
use std::ptr::addr_of_mut;
|
||||
|
||||
fn invalid_array() {
|
||||
|
|
@ -10,7 +10,7 @@ fn invalid_array() {
|
|||
unsafe {
|
||||
let a = addr_of_mut!(a).cast::<[bool; 100]>();
|
||||
let b = addr_of_mut!(b).cast::<[bool; 100]>();
|
||||
typed_swap(a, b); //~ERROR: constructing invalid value
|
||||
typed_swap_nonoverlapping(a, b); //~ERROR: constructing invalid value
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean
|
||||
--> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC
|
||||
|
|
||||
LL | typed_swap(a, b);
|
||||
| ^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
|
||||
LL | typed_swap_nonoverlapping(a, b);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean
|
||||
--> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
|
||||
|
|
||||
LL | typed_swap(a, b);
|
||||
| ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
|
||||
LL | typed_swap_nonoverlapping(a, b);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean
|
||||
--> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
|
||||
|
|
||||
LL | typed_swap_nonoverlapping(a, b);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `invalid_scalar` at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
|
||||
|
|
||||
LL | invalid_scalar();
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,16 +1,18 @@
|
|||
//@revisions: left right
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::intrinsics::typed_swap;
|
||||
use std::intrinsics::typed_swap_nonoverlapping;
|
||||
use std::ptr::addr_of_mut;
|
||||
|
||||
fn invalid_scalar() {
|
||||
let mut a = 1_u8;
|
||||
let mut b = 2_u8;
|
||||
// We run the test twice, with either the left or the right side being invalid.
|
||||
let mut a = if cfg!(left) { 2_u8 } else { 1_u8 };
|
||||
let mut b = if cfg!(right) { 3_u8 } else { 1_u8 };
|
||||
unsafe {
|
||||
let a = addr_of_mut!(a).cast::<bool>();
|
||||
let b = addr_of_mut!(b).cast::<bool>();
|
||||
typed_swap(a, b); //~ERROR: constructing invalid value
|
||||
typed_swap_nonoverlapping(a, b); //~ERROR: constructing invalid value
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
13
src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs
Normal file
13
src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::intrinsics::typed_swap_nonoverlapping;
|
||||
use std::ptr::addr_of_mut;
|
||||
|
||||
fn main() {
|
||||
let mut a = 0_u8;
|
||||
unsafe {
|
||||
let a = addr_of_mut!(a);
|
||||
typed_swap_nonoverlapping(a, a); //~ERROR: called on overlapping ranges
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
|
||||
--> tests/fail/intrinsics/typed-swap-overlap.rs:LL:CC
|
||||
|
|
||||
LL | typed_swap_nonoverlapping(a, a);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at tests/fail/intrinsics/typed-swap-overlap.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# If you want to use this as an .envrc file to create a shell with necessery components
|
||||
# If you want to use this as an .envrc file to create a shell with necessary components
|
||||
# to develop rustc, use the following command in the root of the rusr checkout:
|
||||
#
|
||||
# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# If you want to use this as an .envrc file to create a shell with necessery components
|
||||
# If you want to use this as an .envrc file to create a shell with necessary components
|
||||
# to develop rustc, use the following command in the root of the rusr checkout:
|
||||
#
|
||||
# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc
|
||||
|
|
|
|||
|
|
@ -96,9 +96,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.94"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
|
|
@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.5"
|
||||
version = "1.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||
checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
|
@ -1209,9 +1209,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
|
@ -1338,18 +1338,18 @@ checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.216"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.216"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1446,9 +1446,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.90"
|
||||
version = "2.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
||||
checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1639,9 +1639,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
|||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.8.0"
|
||||
version = "2.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
|
||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use std::fs::create_dir_all;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use clap::Parser;
|
||||
|
|
@ -169,7 +169,7 @@ fn execute_benchmark(cmd: &mut Command, compiler: &Path) {
|
|||
|
||||
const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
|
||||
|
||||
let rustc_perf_dir = PathBuf::from(MANIFEST_DIR).join("../rustc-perf");
|
||||
let rustc_perf_dir = Path::new(MANIFEST_DIR).join("../rustc-perf");
|
||||
|
||||
// We need to set the working directory to `src/tools/perf`, so that it can find the directory
|
||||
// with compile-time benchmarks.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::sync::OnceLock;
|
|||
|
||||
use crate::{Suggestion, sug};
|
||||
|
||||
// FIXME: perhaps this could use `std::lazy` when it is stablizied
|
||||
// FIXME: perhaps this could use `std::lazy` when it is stabilized
|
||||
macro_rules! static_suggestions {
|
||||
($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => {
|
||||
pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec<Suggestion>)]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ autobins = false
|
|||
|
||||
[dependencies]
|
||||
build_helper = { path = "../../build_helper" }
|
||||
cargo_metadata = "0.18"
|
||||
cargo_metadata = "0.19"
|
||||
regex = "1"
|
||||
miropt-test-tools = { path = "../miropt-test-tools" }
|
||||
walkdir = "2"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
run-make/branch-protection-check-IBT/Makefile
|
||||
run-make/cat-and-grep-sanity-check/Makefile
|
||||
run-make/extern-fn-reachable/Makefile
|
||||
run-make/incr-add-rust-src-component/Makefile
|
||||
run-make/jobserver-error/Makefile
|
||||
run-make/libs-through-symlinks/Makefile
|
||||
run-make/split-debuginfo/Makefile
|
||||
run-make/symbol-mangling-hashed/Makefile
|
||||
run-make/translation/Makefile
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
//! Checks the licenses of third-party dependencies.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::fs::read_dir;
|
||||
use std::fs::{File, read_dir};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use build_helper::ci::CiEnv;
|
||||
use cargo_metadata::{Metadata, Package, PackageId};
|
||||
|
||||
#[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"]
|
||||
mod proc_macro_deps;
|
||||
|
||||
/// These are licenses that are allowed for all crates, including the runtime,
|
||||
/// rustc, tools, etc.
|
||||
#[rustfmt::skip]
|
||||
|
|
@ -564,9 +568,11 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
|
|||
///
|
||||
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
|
||||
/// to the cargo executable.
|
||||
pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
|
||||
pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
|
||||
let mut checked_runtime_licenses = false;
|
||||
|
||||
check_proc_macro_dep_list(root, cargo, bless, bad);
|
||||
|
||||
for &(workspace, exceptions, permitted_deps, submodules) in WORKSPACES {
|
||||
if has_missing_submodule(root, submodules) {
|
||||
continue;
|
||||
|
|
@ -600,6 +606,71 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
|
|||
assert!(checked_runtime_licenses);
|
||||
}
|
||||
|
||||
/// Ensure the list of proc-macro crate transitive dependencies is up to date
|
||||
fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
|
||||
let mut cmd = cargo_metadata::MetadataCommand::new();
|
||||
cmd.cargo_path(cargo)
|
||||
.manifest_path(root.join("Cargo.toml"))
|
||||
.features(cargo_metadata::CargoOpt::AllFeatures)
|
||||
.other_options(vec!["--locked".to_owned()]);
|
||||
let metadata = t!(cmd.exec());
|
||||
let is_proc_macro_pkg = |pkg: &Package| pkg.targets.iter().any(|target| target.is_proc_macro());
|
||||
|
||||
let mut proc_macro_deps = HashSet::new();
|
||||
for pkg in metadata.packages.iter().filter(|pkg| is_proc_macro_pkg(*pkg)) {
|
||||
deps_of(&metadata, &pkg.id, &mut proc_macro_deps);
|
||||
}
|
||||
// Remove the proc-macro crates themselves
|
||||
proc_macro_deps.retain(|pkg| !is_proc_macro_pkg(&metadata[pkg]));
|
||||
let proc_macro_deps_iter = proc_macro_deps.into_iter().map(|dep| metadata[dep].name.clone());
|
||||
|
||||
if bless {
|
||||
let mut proc_macro_deps: Vec<_> = proc_macro_deps_iter.collect();
|
||||
proc_macro_deps.sort();
|
||||
proc_macro_deps.dedup();
|
||||
let mut file = File::create(root.join("src/bootstrap/src/utils/proc_macro_deps.rs"))
|
||||
.expect("`proc_macro_deps` should exist");
|
||||
writeln!(
|
||||
&mut file,
|
||||
"/// Do not update manually - use `./x.py test tidy --bless`
|
||||
/// Holds all direct and indirect dependencies of proc-macro crates in tree.
|
||||
/// See <https://github.com/rust-lang/rust/issues/134863>
|
||||
pub static CRATES: &[&str] = &[
|
||||
// tidy-alphabetical-start"
|
||||
)
|
||||
.unwrap();
|
||||
for dep in proc_macro_deps {
|
||||
writeln!(&mut file, " {dep:?},").unwrap();
|
||||
}
|
||||
writeln!(
|
||||
&mut file,
|
||||
" // tidy-alphabetical-end
|
||||
];"
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
let proc_macro_deps: HashSet<_> = proc_macro_deps_iter.collect();
|
||||
let expected =
|
||||
proc_macro_deps::CRATES.iter().map(|s| s.to_string()).collect::<HashSet<_>>();
|
||||
let old_bad = *bad;
|
||||
for missing in proc_macro_deps.difference(&expected) {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"proc-macro crate dependency `{missing}` is not registered in `src/bootstrap/src/utils/proc_macro_deps.rs`",
|
||||
);
|
||||
}
|
||||
for extra in expected.difference(&proc_macro_deps) {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"`{extra}` is not registered in `src/bootstrap/src/utils/proc_macro_deps.rs`, but is not a proc-macro crate dependency",
|
||||
);
|
||||
}
|
||||
if *bad != old_bad {
|
||||
eprintln!("Run `./x.py test tidy --bless` to regenerate the list");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to skip a check if a submodule is not checked out, and not in a CI environment.
|
||||
///
|
||||
/// This helps prevent enforcing developers to fetch submodules for tidy.
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ fn main() {
|
|||
check!(target_specific_tests, &tests_path);
|
||||
|
||||
// Checks that are done on the cargo workspace.
|
||||
check!(deps, &root_path, &cargo);
|
||||
check!(deps, &root_path, &cargo, bless);
|
||||
check!(extdeps, &root_path);
|
||||
|
||||
// Checks over tests.
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[
|
|||
"// gdb",
|
||||
"// lldb",
|
||||
"// cdb",
|
||||
"// normalize-stderr-test",
|
||||
"//@ normalize-stderr-test",
|
||||
"//@ normalize-stderr",
|
||||
];
|
||||
|
||||
fn generate_problems<'a>(
|
||||
|
|
@ -198,8 +197,8 @@ fn should_ignore(line: &str) -> bool {
|
|||
|
||||
// For `ui_test`-style UI test directives, also ignore
|
||||
// - `//@[rev] compile-flags`
|
||||
// - `//@[rev] normalize-stderr-test`
|
||||
|| static_regex!("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*")
|
||||
// - `//@[rev] normalize-stderr`
|
||||
|| static_regex!("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr|error-pattern).*")
|
||||
.is_match(line)
|
||||
// Matching for rustdoc tests commands.
|
||||
// It allows to prevent them emitting warnings like `line longer than 100 chars`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue