Auto merge of #93621 - JohnTitor:rollup-1bcud0x, r=JohnTitor

Rollup of 7 pull requests

Successful merges:

 - #92310 (rustdoc: Fix ICE report)
 - #92802 (Deduplicate lines in long const-eval stack trace)
 - #93515 (Factor convenience functions out of main printer implementation)
 - #93566 (Make rustc use `RUST_BACKTRACE=full` by default)
 - #93589 (Use Option::then in two places)
 - #93600 (fix: Remove extra newlines from junit output)
 - #93606 (Correct incorrect description of preorder traversals)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-02-03 15:49:30 +00:00
commit 4e8fb743cc
12 changed files with 215 additions and 105 deletions

View File

@ -132,6 +132,7 @@
//! methods called `Printer::scan_*`, and the 'PRINT' process is the //! methods called `Printer::scan_*`, and the 'PRINT' process is the
//! method called `Printer::print`. //! method called `Printer::print`.
mod convenience;
mod ring; mod ring;
use ring::RingBuffer; use ring::RingBuffer;
@ -186,12 +187,6 @@ pub enum Token {
End, End,
} }
impl Token {
pub fn is_hardbreak_tok(&self) -> bool {
matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
}
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum PrintFrame { enum PrintFrame {
Fits, Fits,
@ -441,73 +436,4 @@ impl Printer {
self.out.push_str(string); self.out.push_str(string);
self.space -= string.len() as isize; self.space -= string.len() as isize;
} }
// Convenience functions to talk to the printer.
/// "raw box"
pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
self.scan_begin(BeginToken {
indent: IndentStyle::Block { offset: indent as isize },
breaks,
})
}
/// Inconsistent breaking box
pub fn ibox(&mut self, indent: usize) {
self.rbox(indent, Breaks::Inconsistent)
}
/// Consistent breaking box
pub fn cbox(&mut self, indent: usize) {
self.rbox(indent, Breaks::Consistent)
}
pub fn visual_align(&mut self) {
self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
}
pub fn break_offset(&mut self, n: usize, off: isize) {
self.scan_break(BreakToken { offset: off, blank_space: n as isize })
}
pub fn end(&mut self) {
self.scan_end()
}
pub fn eof(mut self) -> String {
self.scan_eof();
self.out
}
pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
let string = wrd.into();
self.scan_string(string)
}
fn spaces(&mut self, n: usize) {
self.break_offset(n, 0)
}
pub fn zerobreak(&mut self) {
self.spaces(0)
}
pub fn space(&mut self) {
self.spaces(1)
}
pub fn hardbreak(&mut self) {
self.spaces(SIZE_INFINITY as usize)
}
pub fn is_beginning_of_line(&self) -> bool {
match self.last_token() {
Some(last_token) => last_token.is_hardbreak_tok(),
None => true,
}
}
pub fn hardbreak_tok_offset(off: isize) -> Token {
Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
}
} }

View File

@ -0,0 +1,77 @@
use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY};
use std::borrow::Cow;
impl Printer {
/// "raw box"
pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
self.scan_begin(BeginToken {
indent: IndentStyle::Block { offset: indent as isize },
breaks,
})
}
/// Inconsistent breaking box
pub fn ibox(&mut self, indent: usize) {
self.rbox(indent, Breaks::Inconsistent)
}
/// Consistent breaking box
pub fn cbox(&mut self, indent: usize) {
self.rbox(indent, Breaks::Consistent)
}
pub fn visual_align(&mut self) {
self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
}
pub fn break_offset(&mut self, n: usize, off: isize) {
self.scan_break(BreakToken { offset: off, blank_space: n as isize })
}
pub fn end(&mut self) {
self.scan_end()
}
pub fn eof(mut self) -> String {
self.scan_eof();
self.out
}
pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
let string = wrd.into();
self.scan_string(string)
}
fn spaces(&mut self, n: usize) {
self.break_offset(n, 0)
}
pub fn zerobreak(&mut self) {
self.spaces(0)
}
pub fn space(&mut self) {
self.spaces(1)
}
pub fn hardbreak(&mut self) {
self.spaces(SIZE_INFINITY as usize)
}
pub fn is_beginning_of_line(&self) -> bool {
match self.last_token() {
Some(last_token) => last_token.is_hardbreak_tok(),
None => true,
}
}
pub fn hardbreak_tok_offset(off: isize) -> Token {
Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
}
}
impl Token {
pub fn is_hardbreak_tok(&self) -> bool {
matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
}
}

View File

@ -156,9 +156,37 @@ impl<'tcx> ConstEvalErr<'tcx> {
} }
// Add spans for the stacktrace. Don't print a single-line backtrace though. // Add spans for the stacktrace. Don't print a single-line backtrace though.
if self.stacktrace.len() > 1 { if self.stacktrace.len() > 1 {
// Helper closure to print duplicated lines.
let mut flush_last_line = |last_frame, times| {
if let Some((line, span)) = last_frame {
err.span_label(span, &line);
// Don't print [... additional calls ...] if the number of lines is small
if times < 3 {
for _ in 0..times {
err.span_label(span, &line);
}
} else {
err.span_label(
span,
format!("[... {} additional calls {} ...]", times, &line),
);
}
}
};
let mut last_frame = None;
let mut times = 0;
for frame_info in &self.stacktrace { for frame_info in &self.stacktrace {
err.span_label(frame_info.span, frame_info.to_string()); let frame = (frame_info.to_string(), frame_info.span);
if last_frame.as_ref() == Some(&frame) {
times += 1;
} else {
flush_last_line(last_frame, times);
last_frame = Some(frame);
times = 0;
}
} }
flush_last_line(last_frame, times);
} }
// Let the caller finish the job. // Let the caller finish the job.
emit(err) emit(err)

View File

@ -66,7 +66,7 @@ pub const EXIT_FAILURE: i32 = 1;
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md"; ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["Z", "C", "crate-type"]; const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"]; const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
@ -1100,31 +1100,31 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<as
/// debugging, since some ICEs only happens with non-default compiler flags /// debugging, since some ICEs only happens with non-default compiler flags
/// (and the users don't always report them). /// (and the users don't always report them).
fn extra_compiler_flags() -> Option<(Vec<String>, bool)> { fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::<Vec<_>>(); let mut args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable();
// Avoid printing help because of empty args. This can suggest the compiler
// itself is not the program root (consider RLS).
if args.len() < 2 {
return None;
}
let matches = handle_options(&args)?;
let mut result = Vec::new(); let mut result = Vec::new();
let mut excluded_cargo_defaults = false; let mut excluded_cargo_defaults = false;
for flag in ICE_REPORT_COMPILER_FLAGS { while let Some(arg) = args.next() {
let prefix = if flag.len() == 1 { "-" } else { "--" }; if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
let content = if arg.len() == a.len() {
for content in &matches.opt_strs(flag) { match args.next() {
// Split always returns the first element Some(arg) => arg.to_string(),
let name = if let Some(first) = content.split('=').next() { first } else { &content }; None => continue,
}
let content = } else if arg.get(a.len()..a.len() + 1) == Some("=") {
if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { name } else { content }; arg[a.len() + 1..].to_string()
if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) {
result.push(format!("{}{} {}", prefix, flag, content));
} else { } else {
arg[a.len()..].to_string()
};
if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) {
excluded_cargo_defaults = true; excluded_cargo_defaults = true;
} else {
result.push(a.to_string());
match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| content.starts_with(*s))
{
Some(s) => result.push(s.to_string()),
None => result.push(content),
}
} }
} }
} }
@ -1240,6 +1240,15 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
/// ///
/// A custom rustc driver can skip calling this to set up a custom ICE hook. /// A custom rustc driver can skip calling this to set up a custom ICE hook.
pub fn install_ice_hook() { pub fn install_ice_hook() {
// If the user has not explicitly overriden "RUST_BACKTRACE", then produce
// full backtraces. When a compiler ICE happens, we want to gather
// as much information as possible to present in the issue opened
// by the user. Compiler developers and other rustc users can
// opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
// (e.g. `RUST_BACKTRACE=1`)
if std::env::var("RUST_BACKTRACE").is_err() {
std::env::set_var("RUST_BACKTRACE", "full");
}
SyncLazy::force(&DEFAULT_HOOK); SyncLazy::force(&DEFAULT_HOOK);
} }

View File

@ -4,8 +4,9 @@ use super::*;
/// Preorder traversal of a graph. /// Preorder traversal of a graph.
/// ///
/// Preorder traversal is when each node is visited before any of its /// Preorder traversal is when each node is visited after at least one of its predecessors. If you
/// successors /// are familar with some basic graph theory, then this performs a depth first search and returns
/// nodes in order of discovery time.
/// ///
/// ```text /// ```text
/// ///
@ -82,8 +83,9 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
/// Postorder traversal of a graph. /// Postorder traversal of a graph.
/// ///
/// Postorder traversal is when each node is visited after all of its /// Postorder traversal is when each node is visited after all of its successors, except when the
/// successors, except when the successor is only reachable by a back-edge /// successor is only reachable by a back-edge. If you are familiar with some basic graph theory,
/// then this performs a depth first search and returns nodes in order of completion time.
/// ///
/// ///
/// ```text /// ```text

View File

@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// The set of places that we are creating fake borrows of. If there are // The set of places that we are creating fake borrows of. If there are
// no match guards then we don't need any fake borrows, so don't track // no match guards then we don't need any fake borrows, so don't track
// them. // them.
let mut fake_borrows = if match_has_guard { Some(FxHashSet::default()) } else { None }; let mut fake_borrows = match_has_guard.then(FxHashSet::default);
let mut otherwise = None; let mut otherwise = None;

View File

@ -182,7 +182,7 @@ impl<K: DepKind> EncoderState<K> {
total_edge_count: 0, total_edge_count: 0,
total_node_count: 0, total_node_count: 0,
result: Ok(()), result: Ok(()),
stats: if record_stats { Some(FxHashMap::default()) } else { None }, stats: record_stats.then(FxHashMap::default),
} }
} }

View File

@ -33,7 +33,6 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
_shuffle_seed: Option<u64>, _shuffle_seed: Option<u64>,
) -> io::Result<()> { ) -> io::Result<()> {
// We write xml header on run start // We write xml header on run start
self.out.write_all(b"\n")?;
self.write_message("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") self.write_message("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
} }
@ -138,7 +137,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
self.write_message("</testsuite>")?; self.write_message("</testsuite>")?;
self.write_message("</testsuites>")?; self.write_message("</testsuites>")?;
self.out.write_all(b"\n\n")?; self.out.write_all(b"\n")?;
Ok(state.failed == 0) Ok(state.failed == 0)
} }

View File

@ -0,0 +1,11 @@
#![allow(unused)]
const fn f<T>(x: T) { //~ WARN function cannot return without recursing
f(x);
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler
}
const X: () = f(1);
fn main() {}

View File

@ -0,0 +1,31 @@
warning: function cannot return without recursing
--> $DIR/recursive.rs:3:1
|
LL | const fn f<T>(x: T) {
| ^^^^^^^^^^^^^^^^^^^ cannot return without recursing
LL | f(x);
| ---- recursive call site
|
= note: `#[warn(unconditional_recursion)]` on by default
= help: a `loop` may express intention better if this is on purpose
error: any use of this value will cause an error
--> $DIR/recursive.rs:4:5
|
LL | f(x);
| ^^^^
| |
| reached the configured maximum number of stack frames
| inside `f::<i32>` at $DIR/recursive.rs:4:5
| [... 126 additional calls inside `f::<i32>` at $DIR/recursive.rs:4:5 ...]
| inside `X` at $DIR/recursive.rs:9:15
...
LL | const X: () = f(1);
| -------------------
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: aborting due to previous error; 1 warning emitted

View File

@ -0,0 +1,9 @@
// unset-rustc-env:RUST_BACKTRACE
// compile-flags:-Z treat-err-as-bug=1
// error-pattern:stack backtrace:
// failure-status:101
// normalize-stderr-test "note: .*" -> ""
// normalize-stderr-test "thread 'rustc' .*" -> ""
// normalize-stderr-test " .*\n" -> ""
fn main() { missing_ident; }

View File

@ -0,0 +1,18 @@
error[E0425]: cannot find value `missing_ident` in this scope
LL | fn main() { missing_ident; }
stack backtrace:
error: internal compiler error: unexpected panic
query stack during panic:
end of query stack