Merge from rustc
This commit is contained in:
commit
f69ea4d82f
872 changed files with 7959 additions and 5020 deletions
|
|
@ -45,6 +45,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
|||
pats.iter().all(unary_pattern)
|
||||
}
|
||||
match &pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Slice(_, _, _)
|
||||
| PatKind::Range(_, _, _)
|
||||
| PatKind::Binding(..)
|
||||
|
|
|
|||
|
|
@ -253,6 +253,7 @@ fn iter_matching_struct_fields<'a>(
|
|||
impl<'a> NormalizedPat<'a> {
|
||||
fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
|
||||
PatKind::Binding(.., Some(pat))
|
||||
| PatKind::Box(pat)
|
||||
|
|
|
|||
|
|
@ -406,6 +406,7 @@ impl<'a> PatState<'a> {
|
|||
pats.iter().map(|p| p.pat),
|
||||
),
|
||||
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild
|
||||
| PatKind::Binding(_, _, _, None)
|
||||
| PatKind::Expr(_)
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
|||
|
||||
// We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`.
|
||||
let changed = match &mut focus_kind {
|
||||
Missing => unreachable!(),
|
||||
// These pattern forms are "leafs" and do not have sub-patterns.
|
||||
// Therefore they are not some form of constructor `C`,
|
||||
// with which a pattern `C(p_0)` may be formed,
|
||||
|
|
|
|||
|
|
@ -676,6 +676,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
match pat.value.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => kind!("Wild"),
|
||||
PatKind::Never => kind!("Never"),
|
||||
PatKind::Binding(ann, _, name, sub) => {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ pub fn eq_id(l: Ident, r: Ident) -> bool {
|
|||
pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
||||
use PatKind::*;
|
||||
match (&l.kind, &r.kind) {
|
||||
(Missing, _) | (_, Missing) => unreachable!(),
|
||||
(Paren(l), _) => eq_pat(l, r),
|
||||
(_, Paren(r)) => eq_pat(l, r),
|
||||
(Wild, Wild) | (Rest, Rest) => true,
|
||||
|
|
|
|||
|
|
@ -1124,6 +1124,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
pub fn hash_pat(&mut self, pat: &Pat<'_>) {
|
||||
std::mem::discriminant(&pat.kind).hash(&mut self.s);
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
|
||||
std::mem::discriminant(&by_ref).hash(&mut self.s);
|
||||
std::mem::discriminant(&mutability).hash(&mut self.s);
|
||||
|
|
|
|||
|
|
@ -1858,6 +1858,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
|||
}
|
||||
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
|
||||
PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
|
||||
PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
|
||||
|
|
|
|||
|
|
@ -7,25 +7,26 @@ edition = "2021"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
anstyle-svg = "0.1.3"
|
||||
build_helper = { path = "../../build_helper" }
|
||||
colored = "2"
|
||||
diff = "0.1.10"
|
||||
unified-diff = "0.2.1"
|
||||
getopts = "0.2"
|
||||
glob = "0.3.0"
|
||||
home = "0.5.5"
|
||||
indexmap = "2.0.0"
|
||||
miropt-test-tools = { path = "../miropt-test-tools" }
|
||||
build_helper = { path = "../../build_helper" }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] }
|
||||
regex = "1.0"
|
||||
rustfix = "0.8.1"
|
||||
semver = { version = "1.0.23", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
rustfix = "0.8.1"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] }
|
||||
unified-diff = "0.2.1"
|
||||
walkdir = "2"
|
||||
glob = "0.3.0"
|
||||
anyhow = "1"
|
||||
home = "0.5.5"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
|
|
|||
|
|
@ -275,9 +275,6 @@ pub struct Config {
|
|||
/// Explicitly enable or disable running.
|
||||
pub run: Option<bool>,
|
||||
|
||||
/// Write out a parseable log of tests that were run
|
||||
pub logfile: Option<PathBuf>,
|
||||
|
||||
/// A command line to prefix program execution with,
|
||||
/// for running under valgrind for example.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||
"dont-check-compiler-stderr",
|
||||
"dont-check-compiler-stdout",
|
||||
"dont-check-failure-status",
|
||||
"dont-require-annotations",
|
||||
"edition",
|
||||
"error-pattern",
|
||||
"exact-llvm-major-version",
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ use std::fs::File;
|
|||
use std::io::BufReader;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use regex::Regex;
|
||||
use tracing::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ErrorKind {
|
||||
Help,
|
||||
Error,
|
||||
|
|
@ -18,30 +17,48 @@ pub enum ErrorKind {
|
|||
Warning,
|
||||
}
|
||||
|
||||
impl FromStr for ErrorKind {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_uppercase();
|
||||
let part0: &str = s.split(':').next().unwrap();
|
||||
match part0 {
|
||||
"HELP" => Ok(ErrorKind::Help),
|
||||
"ERROR" => Ok(ErrorKind::Error),
|
||||
"NOTE" => Ok(ErrorKind::Note),
|
||||
"SUGGESTION" => Ok(ErrorKind::Suggestion),
|
||||
"WARN" | "WARNING" => Ok(ErrorKind::Warning),
|
||||
_ => Err(()),
|
||||
impl ErrorKind {
|
||||
pub fn from_compiler_str(s: &str) -> ErrorKind {
|
||||
match s {
|
||||
"help" => ErrorKind::Help,
|
||||
"error" | "error: internal compiler error" => ErrorKind::Error,
|
||||
"note" | "failure-note" => ErrorKind::Note,
|
||||
"warning" => ErrorKind::Warning,
|
||||
_ => panic!("unexpected compiler diagnostic kind `{s}`"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Either the canonical uppercase string, or some additional versions for compatibility.
|
||||
/// FIXME: consider keeping only the canonical versions here.
|
||||
fn from_user_str(s: &str) -> Option<ErrorKind> {
|
||||
Some(match s {
|
||||
"HELP" | "help" => ErrorKind::Help,
|
||||
"ERROR" | "error" => ErrorKind::Error,
|
||||
"NOTE" | "note" => ErrorKind::Note,
|
||||
"SUGGESTION" => ErrorKind::Suggestion,
|
||||
"WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expect_from_user_str(s: &str) -> ErrorKind {
|
||||
ErrorKind::from_user_str(s).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"unexpected diagnostic kind `{s}`, expected \
|
||||
`ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ErrorKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ErrorKind::Help => write!(f, "help message"),
|
||||
ErrorKind::Error => write!(f, "error"),
|
||||
ErrorKind::Note => write!(f, "note"),
|
||||
ErrorKind::Suggestion => write!(f, "suggestion"),
|
||||
ErrorKind::Warning => write!(f, "warning"),
|
||||
ErrorKind::Help => write!(f, "HELP"),
|
||||
ErrorKind::Error => write!(f, "ERROR"),
|
||||
ErrorKind::Note => write!(f, "NOTE"),
|
||||
ErrorKind::Suggestion => write!(f, "SUGGESTION"),
|
||||
ErrorKind::Warning => write!(f, "WARN"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +70,10 @@ pub struct Error {
|
|||
/// `None` if not specified or unknown message kind.
|
||||
pub kind: Option<ErrorKind>,
|
||||
pub msg: String,
|
||||
/// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations
|
||||
/// are not mandatory, even if they would otherwise be mandatory for primary errors.
|
||||
/// Only makes sense for "actual" errors, not for "expected" errors.
|
||||
pub require_annotation: bool,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
|
|
@ -60,7 +81,7 @@ impl Error {
|
|||
use colored::Colorize;
|
||||
format!(
|
||||
"{: <10}line {: >3}: {}",
|
||||
self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(),
|
||||
self.kind.map(|kind| kind.to_string()).unwrap_or_default(),
|
||||
self.line_num_str(),
|
||||
self.msg.cyan(),
|
||||
)
|
||||
|
|
@ -150,18 +171,12 @@ fn parse_expected(
|
|||
}
|
||||
|
||||
// Get the part of the comment after the sigil (e.g. `~^^` or ~|).
|
||||
let whole_match = captures.get(0).unwrap();
|
||||
let (_, mut msg) = line.split_at(whole_match.end());
|
||||
|
||||
let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment");
|
||||
|
||||
// If we find `//~ ERROR foo` or something like that, skip the first word.
|
||||
let kind = first_word.parse::<ErrorKind>().ok();
|
||||
if kind.is_some() {
|
||||
msg = &msg.trim_start().split_at(first_word.len()).1;
|
||||
}
|
||||
|
||||
let msg = msg.trim().to_owned();
|
||||
let tag = captures.get(0).unwrap();
|
||||
let rest = line[tag.end()..].trim_start();
|
||||
let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
|
||||
let kind = ErrorKind::from_user_str(kind_str);
|
||||
let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest };
|
||||
let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
|
||||
|
||||
let line_num_adjust = &captures["adjust"];
|
||||
let (follow_prev, line_num) = if line_num_adjust == "|" {
|
||||
|
|
@ -177,12 +192,12 @@ fn parse_expected(
|
|||
debug!(
|
||||
"line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
|
||||
line_num,
|
||||
whole_match.as_str(),
|
||||
tag.as_str(),
|
||||
follow_prev,
|
||||
kind,
|
||||
msg
|
||||
);
|
||||
Some((follow_prev, Error { line_num, kind, msg }))
|
||||
Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ fn test_opts(config: &Config) -> test::TestOpts {
|
|||
filter_exact: config.filter_exact,
|
||||
run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
|
||||
format: config.format.to_libtest(),
|
||||
logfile: config.logfile.clone(),
|
||||
logfile: None,
|
||||
run_tests: true,
|
||||
bench_benchmarks: true,
|
||||
nocapture: config.nocapture,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
|
|
@ -11,6 +11,7 @@ use tracing::*;
|
|||
|
||||
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
|
||||
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
|
||||
use crate::header::needs::CachedNeedsConditions;
|
||||
|
|
@ -196,6 +197,8 @@ pub struct TestProps {
|
|||
/// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios
|
||||
/// that don't otherwise want/need `-Z build-std`.
|
||||
pub add_core_stubs: bool,
|
||||
/// Whether line annotatins are required for the given error kind.
|
||||
pub require_annotations: HashMap<ErrorKind, bool>,
|
||||
}
|
||||
|
||||
mod directives {
|
||||
|
|
@ -212,6 +215,7 @@ mod directives {
|
|||
pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
|
||||
pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout";
|
||||
pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr";
|
||||
pub const DONT_REQUIRE_ANNOTATIONS: &'static str = "dont-require-annotations";
|
||||
pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic";
|
||||
pub const PRETTY_MODE: &'static str = "pretty-mode";
|
||||
pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only";
|
||||
|
|
@ -297,6 +301,13 @@ impl TestProps {
|
|||
no_auto_check_cfg: false,
|
||||
has_enzyme: false,
|
||||
add_core_stubs: false,
|
||||
require_annotations: HashMap::from([
|
||||
(ErrorKind::Help, true),
|
||||
(ErrorKind::Note, true),
|
||||
(ErrorKind::Error, true),
|
||||
(ErrorKind::Warning, true),
|
||||
(ErrorKind::Suggestion, false),
|
||||
]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -570,6 +581,13 @@ impl TestProps {
|
|||
config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg);
|
||||
|
||||
self.update_add_core_stubs(ln, config);
|
||||
|
||||
if let Some(err_kind) =
|
||||
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
|
||||
{
|
||||
self.require_annotations
|
||||
.insert(ErrorKind::expect_from_user_str(&err_kind), false);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -459,9 +459,6 @@ fn profiler_runtime() {
|
|||
#[test]
|
||||
fn asm_support() {
|
||||
let asms = [
|
||||
#[cfg(bootstrap)]
|
||||
("avr-unknown-gnu-atmega328", false),
|
||||
#[cfg(not(bootstrap))]
|
||||
("avr-none", false),
|
||||
("i686-unknown-netbsd", true),
|
||||
("riscv32gc-unknown-linux-gnu", true),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
//! These structs are a subset of the ones found in `rustc_errors::json`.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use regex::Regex;
|
||||
|
|
@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String {
|
|||
}
|
||||
|
||||
pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
|
||||
output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
|
||||
}
|
||||
|
||||
fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
|
||||
// The compiler sometimes intermingles non-JSON stuff into the
|
||||
// output. This hack just skips over such lines. Yuck.
|
||||
if line.starts_with('{') {
|
||||
match serde_json::from_str::<Diagnostic>(line) {
|
||||
Ok(diagnostic) => {
|
||||
let mut expected_errors = vec![];
|
||||
push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
|
||||
expected_errors
|
||||
}
|
||||
Err(error) => {
|
||||
// Ignore the future compat report message - this is handled
|
||||
// by `extract_rendered`
|
||||
if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
|
||||
vec![]
|
||||
} else {
|
||||
proc_res.fatal(
|
||||
let mut errors = Vec::new();
|
||||
for line in output.lines() {
|
||||
// The compiler sometimes intermingles non-JSON stuff into the
|
||||
// output. This hack just skips over such lines. Yuck.
|
||||
if line.starts_with('{') {
|
||||
match serde_json::from_str::<Diagnostic>(line) {
|
||||
Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
|
||||
Err(error) => {
|
||||
// Ignore the future compat report message - this is handled
|
||||
// by `extract_rendered`
|
||||
if serde_json::from_str::<FutureIncompatReport>(line).is_err() {
|
||||
proc_res.fatal(
|
||||
Some(&format!(
|
||||
"failed to decode compiler output as json: \
|
||||
`{}`\nline: {}\noutput: {}",
|
||||
"failed to decode compiler output as json: `{}`\nline: {}\noutput: {}",
|
||||
error, line, output
|
||||
)),
|
||||
|| (),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
errors
|
||||
}
|
||||
|
||||
fn push_expected_errors(
|
||||
expected_errors: &mut Vec<Error>,
|
||||
fn push_actual_errors(
|
||||
errors: &mut Vec<Error>,
|
||||
diagnostic: &Diagnostic,
|
||||
default_spans: &[&DiagnosticSpan],
|
||||
file_name: &str,
|
||||
|
|
@ -236,44 +226,47 @@ fn push_expected_errors(
|
|||
}
|
||||
};
|
||||
|
||||
// Convert multi-line messages into multiple expected
|
||||
// errors. We expect to replace these with something
|
||||
// more structured shortly anyhow.
|
||||
// Convert multi-line messages into multiple errors.
|
||||
// We expect to replace these with something more structured anyhow.
|
||||
let mut message_lines = diagnostic.message.lines();
|
||||
if let Some(first_line) = message_lines.next() {
|
||||
let ignore = |s| {
|
||||
static RE: OnceLock<Regex> = OnceLock::new();
|
||||
RE.get_or_init(|| {
|
||||
Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap()
|
||||
})
|
||||
.is_match(s)
|
||||
};
|
||||
|
||||
if primary_spans.is_empty() && !ignore(first_line) {
|
||||
let msg = with_code(None, first_line);
|
||||
let kind = ErrorKind::from_str(&diagnostic.level).ok();
|
||||
expected_errors.push(Error { line_num: None, kind, msg });
|
||||
} else {
|
||||
for span in primary_spans {
|
||||
let msg = with_code(Some(span), first_line);
|
||||
let kind = ErrorKind::from_str(&diagnostic.level).ok();
|
||||
expected_errors.push(Error { line_num: Some(span.line_start), kind, msg });
|
||||
}
|
||||
let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level));
|
||||
let first_line = message_lines.next().unwrap_or(&diagnostic.message);
|
||||
if primary_spans.is_empty() {
|
||||
static RE: OnceLock<Regex> = OnceLock::new();
|
||||
let re_init =
|
||||
|| Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
|
||||
errors.push(Error {
|
||||
line_num: None,
|
||||
kind,
|
||||
msg: with_code(None, first_line),
|
||||
require_annotation: diagnostic.level != "failure-note"
|
||||
&& !RE.get_or_init(re_init).is_match(first_line),
|
||||
});
|
||||
} else {
|
||||
for span in primary_spans {
|
||||
errors.push(Error {
|
||||
line_num: Some(span.line_start),
|
||||
kind,
|
||||
msg: with_code(Some(span), first_line),
|
||||
require_annotation: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
for next_line in message_lines {
|
||||
if primary_spans.is_empty() {
|
||||
expected_errors.push(Error {
|
||||
errors.push(Error {
|
||||
line_num: None,
|
||||
kind: None,
|
||||
kind,
|
||||
msg: with_code(None, next_line),
|
||||
require_annotation: false,
|
||||
});
|
||||
} else {
|
||||
for span in primary_spans {
|
||||
expected_errors.push(Error {
|
||||
errors.push(Error {
|
||||
line_num: Some(span.line_start),
|
||||
kind: None,
|
||||
kind,
|
||||
msg: with_code(Some(span), next_line),
|
||||
require_annotation: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -283,10 +276,11 @@ fn push_expected_errors(
|
|||
for span in primary_spans {
|
||||
if let Some(ref suggested_replacement) = span.suggested_replacement {
|
||||
for (index, line) in suggested_replacement.lines().enumerate() {
|
||||
expected_errors.push(Error {
|
||||
errors.push(Error {
|
||||
line_num: Some(span.line_start + index),
|
||||
kind: Some(ErrorKind::Suggestion),
|
||||
msg: line.to_string(),
|
||||
require_annotation: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -295,39 +289,41 @@ fn push_expected_errors(
|
|||
// Add notes for the backtrace
|
||||
for span in primary_spans {
|
||||
if let Some(frame) = &span.expansion {
|
||||
push_backtrace(expected_errors, frame, file_name);
|
||||
push_backtrace(errors, frame, file_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Add notes for any labels that appear in the message.
|
||||
for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
|
||||
expected_errors.push(Error {
|
||||
errors.push(Error {
|
||||
line_num: Some(span.line_start),
|
||||
kind: Some(ErrorKind::Note),
|
||||
msg: span.label.clone().unwrap(),
|
||||
require_annotation: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Flatten out the children.
|
||||
for child in &diagnostic.children {
|
||||
push_expected_errors(expected_errors, child, primary_spans, file_name);
|
||||
push_actual_errors(errors, child, primary_spans, file_name);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_backtrace(
|
||||
expected_errors: &mut Vec<Error>,
|
||||
errors: &mut Vec<Error>,
|
||||
expansion: &DiagnosticSpanMacroExpansion,
|
||||
file_name: &str,
|
||||
) {
|
||||
if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
|
||||
expected_errors.push(Error {
|
||||
errors.push(Error {
|
||||
line_num: Some(expansion.span.line_start),
|
||||
kind: Some(ErrorKind::Note),
|
||||
msg: format!("in this expansion of {}", expansion.macro_decl_name),
|
||||
require_annotation: true,
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(previous_expansion) = &expansion.span.expansion {
|
||||
push_backtrace(expected_errors, previous_expansion, file_name);
|
||||
push_backtrace(errors, previous_expansion, file_name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
.optflag("", "quiet", "print one character per test instead of one line")
|
||||
.optopt("", "color", "coloring: auto, always, never", "WHEN")
|
||||
.optflag("", "json", "emit json output instead of plaintext output")
|
||||
.optopt("", "logfile", "file to log test execution to", "FILE")
|
||||
.optopt("", "target", "the target to build for", "TARGET")
|
||||
.optopt("", "host", "the host to build for", "HOST")
|
||||
.optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH")
|
||||
|
|
@ -378,7 +377,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
"never" => Some(false),
|
||||
_ => panic!("unknown `--run` option `{}` given", mode),
|
||||
}),
|
||||
logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
|
||||
runner: matches.opt_str("runner"),
|
||||
host_rustcflags: matches.opt_strs("host-rustcflags"),
|
||||
target_rustcflags: matches.opt_strs("target-rustcflags"),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use std::process::{Child, Command, ExitStatus, Output, Stdio};
|
|||
use std::sync::Arc;
|
||||
use std::{env, iter, str};
|
||||
|
||||
use anyhow::Context;
|
||||
use colored::Colorize;
|
||||
use regex::{Captures, Regex};
|
||||
use tracing::*;
|
||||
|
|
@ -143,11 +142,11 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
|
|||
}
|
||||
|
||||
let cx = TestCx { config: &config, props: &props, testpaths, revision };
|
||||
create_dir_all(&cx.output_base_dir())
|
||||
.with_context(|| {
|
||||
format!("failed to create output base directory {}", cx.output_base_dir().display())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
if let Err(e) = create_dir_all(&cx.output_base_dir()) {
|
||||
panic!("failed to create output base directory {}: {e}", cx.output_base_dir().display());
|
||||
}
|
||||
|
||||
if props.incremental {
|
||||
cx.init_incremental_test();
|
||||
}
|
||||
|
|
@ -710,10 +709,6 @@ impl<'test> TestCx<'test> {
|
|||
self.testpaths.file.display().to_string()
|
||||
};
|
||||
|
||||
// If the testcase being checked contains at least one expected "help"
|
||||
// message, then we'll ensure that all "help" messages are expected.
|
||||
// Otherwise, all "help" messages reported by the compiler will be ignored.
|
||||
// This logic also applies to "note" messages.
|
||||
let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
|
||||
let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
|
||||
|
||||
|
|
@ -801,22 +796,24 @@ impl<'test> TestCx<'test> {
|
|||
}
|
||||
|
||||
/// Returns `true` if we should report an error about `actual_error`,
|
||||
/// which did not match any of the expected error. We always require
|
||||
/// errors/warnings to be explicitly listed, but only require
|
||||
/// helps/notes if there are explicit helps/notes given.
|
||||
/// which did not match any of the expected error.
|
||||
fn is_unexpected_compiler_message(
|
||||
&self,
|
||||
actual_error: &Error,
|
||||
expect_help: bool,
|
||||
expect_note: bool,
|
||||
) -> bool {
|
||||
!actual_error.msg.is_empty()
|
||||
&& match actual_error.kind {
|
||||
Some(ErrorKind::Help) => expect_help,
|
||||
Some(ErrorKind::Note) => expect_note,
|
||||
Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true,
|
||||
Some(ErrorKind::Suggestion) | None => false,
|
||||
}
|
||||
actual_error.require_annotation
|
||||
&& actual_error.kind.map_or(false, |err_kind| {
|
||||
// If the test being checked doesn't contain any "help" or "note" annotations, then
|
||||
// we don't require annotating "help" or "note" (respecively) diagnostics at all.
|
||||
let default_require_annotations = self.props.require_annotations[&err_kind];
|
||||
match err_kind {
|
||||
ErrorKind::Help => expect_help && default_require_annotations,
|
||||
ErrorKind::Note => expect_note && default_require_annotations,
|
||||
_ => default_require_annotations,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ description = "Produces a manifest of all the copyrighted materials in the Rust
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.65"
|
||||
askama = "0.13.0"
|
||||
cargo_metadata = "0.18.1"
|
||||
rinja = "0.3.0"
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = "1.0.85"
|
||||
thiserror = "1"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Error;
|
||||
use rinja::Template;
|
||||
use askama::Template;
|
||||
|
||||
mod cargo_metadata;
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ struct Metadata {
|
|||
}
|
||||
|
||||
/// Describes one node in our metadata tree
|
||||
#[derive(serde::Deserialize, rinja::Template, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(serde::Deserialize, Template, Clone, Debug, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case", tag = "type")]
|
||||
#[template(path = "Node.html")]
|
||||
pub(crate) enum Node {
|
||||
|
|
|
|||
|
|
@ -6882,109 +6882,14 @@ pub fn foo() {}
|
|||
|
||||
#[test]
|
||||
fn hover_feature() {
|
||||
check(
|
||||
r#"#![feature(intrinsics$0)]"#,
|
||||
expect![[r#"
|
||||
*intrinsics*
|
||||
```
|
||||
intrinsics
|
||||
```
|
||||
___
|
||||
|
||||
# `intrinsics`
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
Intrinsics are rarely intended to be stable directly, but are usually
|
||||
exported in some sort of stable manner. Prefer using the stable interfaces to
|
||||
the intrinsic directly when you can.
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
## Intrinsics with fallback logic
|
||||
|
||||
Many intrinsics can be written in pure rust, albeit inefficiently or without supporting
|
||||
some features that only exist on some backends. Backends can simply not implement those
|
||||
intrinsics without causing any code miscompilations or failures to compile.
|
||||
All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`)
|
||||
by the codegen backend, but not the MIR inliner.
|
||||
|
||||
```rust
|
||||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[rustc_intrinsic]
|
||||
const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
|
||||
```
|
||||
|
||||
Since these are just regular functions, it is perfectly ok to create the intrinsic twice:
|
||||
|
||||
```rust
|
||||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[rustc_intrinsic]
|
||||
const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
|
||||
|
||||
mod foo {
|
||||
#[rustc_intrinsic]
|
||||
const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {
|
||||
panic!("noisy const dealloc")
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The behaviour on backends that override the intrinsic is exactly the same. On other
|
||||
backends, the intrinsic behaviour depends on which implementation is called, just like
|
||||
with any regular function.
|
||||
|
||||
## Intrinsics lowered to MIR instructions
|
||||
|
||||
Various intrinsics have native MIR operations that they correspond to. Instead of requiring
|
||||
backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
|
||||
will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
|
||||
at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
|
||||
or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
|
||||
anymore after MIR analyses.
|
||||
|
||||
## Intrinsics without fallback logic
|
||||
|
||||
These must be implemented by all backends.
|
||||
|
||||
### `#[rustc_intrinsic]` declarations
|
||||
|
||||
These are written like intrinsics with fallback bodies, but the body is irrelevant.
|
||||
Use `loop {}` for the body or call the intrinsic recursively and add
|
||||
`#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
|
||||
invoke the body.
|
||||
|
||||
### Legacy extern ABI based intrinsics
|
||||
|
||||
These are imported as if they were FFI functions, with the special
|
||||
`rust-intrinsic` ABI. For example, if one was in a freestanding
|
||||
context, but wished to be able to `transmute` between types, and
|
||||
perform efficient pointer arithmetic, one would import those functions
|
||||
via a declaration like
|
||||
|
||||
```rust
|
||||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
# fn main() {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn transmute<T, U>(x: T) -> U;
|
||||
|
||||
fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
}
|
||||
```
|
||||
|
||||
As with any other FFI functions, these are by default always `unsafe` to call.
|
||||
You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
|
||||
|
||||
"#]],
|
||||
)
|
||||
let (analysis, position) = fixture::position(r#"#![feature(intrinsics$0)]"#);
|
||||
analysis
|
||||
.hover(
|
||||
&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG },
|
||||
FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit e22e08623a349b13a3296971a05394d44f769744
|
||||
Subproject commit c0f3b53c8e5de87714d18a5f42998859302ae03a
|
||||
|
|
@ -2442,11 +2442,7 @@ pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param
|
|||
}
|
||||
|
||||
pub(crate) fn is_named_param(param: &ast::Param) -> bool {
|
||||
if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
|
||||
ident.name != symbol::kw::Empty
|
||||
} else {
|
||||
true
|
||||
}
|
||||
!matches!(param.pat.kind, ast::PatKind::Missing)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ pub(crate) fn is_short_pattern(
|
|||
|
||||
fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool {
|
||||
match &pat.kind {
|
||||
ast::PatKind::Missing => unreachable!(),
|
||||
ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => {
|
||||
true
|
||||
}
|
||||
|
|
@ -100,6 +101,7 @@ impl Rewrite for Pat {
|
|||
|
||||
fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
|
||||
match self.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Or(ref pats) => {
|
||||
let pat_strs = pats
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -164,7 +164,6 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[
|
|||
("brotli-decompressor", "BSD-3-Clause/MIT"),
|
||||
("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"),
|
||||
("inferno", "CDDL-1.0"),
|
||||
("instant", "BSD-3-Clause"),
|
||||
("ring", NON_STANDARD_LICENSE), // see EXCEPTIONS_NON_STANDARD_LICENSE_DEPS for more.
|
||||
("ryu", "Apache-2.0 OR BSL-1.0"),
|
||||
("snap", "BSD-3-Clause"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue