From 4413141ea96cfe4edbe417f352b13160556bd48e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 26 Dec 2021 20:32:17 -0800 Subject: [PATCH 1/7] rustdoc: Fix ICE report --- compiler/rustc_driver/src/lib.rs | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 12e0b7a4977e1..42a0ca3d052c7 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -64,7 +64,7 @@ pub const EXIT_FAILURE: i32 = 1; 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"; -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"]; @@ -1108,31 +1108,31 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec Option<(Vec, bool)> { - let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::>(); + 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 excluded_cargo_defaults = false; - for flag in ICE_REPORT_COMPILER_FLAGS { - let prefix = if flag.len() == 1 { "-" } else { "--" }; - - for content in &matches.opt_strs(flag) { - // Split always returns the first element - let name = if let Some(first) = content.split('=').next() { first } else { &content }; - - let content = - if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { name } else { content }; - - if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) { - result.push(format!("{}{} {}", prefix, flag, content)); + while let Some(arg) = args.next() { + if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) { + let content = if arg.len() == a.len() { + match args.next() { + Some(arg) => arg.to_string(), + None => continue, + } + } else if arg.get(a.len()..a.len() + 1) == Some("=") { + arg[a.len() + 1..].to_string() } else { + arg[a.len()..].to_string() + }; + if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) { 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), + } } } } From 73ad8df70d94d318fea0df3079504bd23e5b4901 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 11 Jan 2022 17:55:56 -0800 Subject: [PATCH 2/7] Deduplicate lines in long const-eval stack trace --- .../rustc_const_eval/src/const_eval/error.rs | 30 +++++++++++++++++- src/test/ui/consts/recursive.rs | 11 +++++++ src/test/ui/consts/recursive.stderr | 31 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/recursive.rs create mode 100644 src/test/ui/consts/recursive.stderr diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 87298023980ed..89a0f8245e5fb 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -156,9 +156,37 @@ impl<'tcx> ConstEvalErr<'tcx> { } // Add spans for the stacktrace. Don't print a single-line backtrace though. 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 { - 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. emit(err) diff --git a/src/test/ui/consts/recursive.rs b/src/test/ui/consts/recursive.rs new file mode 100644 index 0000000000000..664940c52cfc5 --- /dev/null +++ b/src/test/ui/consts/recursive.rs @@ -0,0 +1,11 @@ +#![allow(unused)] + +const fn f(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() {} diff --git a/src/test/ui/consts/recursive.stderr b/src/test/ui/consts/recursive.stderr new file mode 100644 index 0000000000000..31ac1fff4e84e --- /dev/null +++ b/src/test/ui/consts/recursive.stderr @@ -0,0 +1,31 @@ +warning: function cannot return without recursing + --> $DIR/recursive.rs:3:1 + | +LL | const fn f(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::` at $DIR/recursive.rs:4:5 + | [... 126 additional calls inside `f::` 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 + +error: aborting due to previous error; 1 warning emitted + From 2d7ffbbc40cb8ddd85ed29ad88d217e10a17f8ac Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 21 Jan 2022 13:08:54 -0800 Subject: [PATCH 3/7] Factor convenience functions out of main printer implementation --- compiler/rustc_ast_pretty/src/pp.rs | 76 +----------------- .../rustc_ast_pretty/src/pp/convenience.rs | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 75 deletions(-) create mode 100644 compiler/rustc_ast_pretty/src/pp/convenience.rs diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index e1f43cb20dc38..eb27d5add9f37 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -132,6 +132,7 @@ //! methods called `Printer::scan_*`, and the 'PRINT' process is the //! method called `Printer::print`. +mod convenience; mod ring; use ring::RingBuffer; @@ -185,12 +186,6 @@ pub enum Token { End, } -impl Token { - pub fn is_hardbreak_tok(&self) -> bool { - matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY })) - } -} - #[derive(Copy, Clone)] enum PrintFrame { Fits, @@ -439,73 +434,4 @@ impl Printer { self.out.push_str(string); 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>>(&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 }) - } } diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs new file mode 100644 index 0000000000000..1b9ac705883af --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs @@ -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>>(&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 })) + } +} From 891368f6013398c9f10fe9383f41f02476a48e24 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 1 Feb 2022 19:27:16 -0500 Subject: [PATCH 4/7] Make rustc use `RUST_BACKTRACE=full` by default Compiler panics should be rare - when they do occur, we want the report filed by the user to contain as much information as possible. This is especially important when the panic is due to an incremental compilation bug, since we may not have enough information to reproduce it. This PR sets `RUST_BACKTRACE=full` inside `rustc` if the user has not explicitly set `RUST_BACKTRACE`. This is more verbose than `RUST_BACKTRACE=1`, but this may make it easier to debug incremental compilation issues. Users who find this too verbose can still manually set `RUST_BACKTRACE` before invoking the compiler. This only affects `rustc` (and any tool using `rustc_driver::install_ice_hook`). It does *not* affect any user crates or the standard library - backtraces will continue to be off by default in any application *compiled* by rustc. --- compiler/rustc_driver/src/lib.rs | 9 +++++++++ src/test/ui/panics/default-backtrace-ice.rs | 9 +++++++++ .../ui/panics/default-backtrace-ice.stderr | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 src/test/ui/panics/default-backtrace-ice.rs create mode 100644 src/test/ui/panics/default-backtrace-ice.stderr diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 0f490c3310245..85de860ceaf97 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -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. 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); } diff --git a/src/test/ui/panics/default-backtrace-ice.rs b/src/test/ui/panics/default-backtrace-ice.rs new file mode 100644 index 0000000000000..fd86a3f9dfaff --- /dev/null +++ b/src/test/ui/panics/default-backtrace-ice.rs @@ -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; } diff --git a/src/test/ui/panics/default-backtrace-ice.stderr b/src/test/ui/panics/default-backtrace-ice.stderr new file mode 100644 index 0000000000000..a0025d7e221ae --- /dev/null +++ b/src/test/ui/panics/default-backtrace-ice.stderr @@ -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 From 08be313febc8146a3a8f57d46b33602bdbd1d30e Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 2 Feb 2022 16:08:05 +0100 Subject: [PATCH 5/7] Use Option::then in two places --- compiler/rustc_mir_build/src/build/matches/mod.rs | 2 +- compiler/rustc_query_system/src/dep_graph/serialized.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 3294f2cf64172..1bf692cae6afb 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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 // 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; diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 283eda7c85e64..c95dff13d6615 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -182,7 +182,7 @@ impl EncoderState { total_edge_count: 0, total_node_count: 0, result: Ok(()), - stats: if record_stats { Some(FxHashMap::default()) } else { None }, + stats: record_stats.then(FxHashMap::default), } } From 088474a408c19180badba6705367520daf4efc2b Mon Sep 17 00:00:00 2001 From: Serg Tereshchenko Date: Tue, 1 Feb 2022 21:41:24 +0200 Subject: [PATCH 6/7] fix: Remove extra newlines from junit output --- library/test/src/formatters/junit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index fa23cf2689671..f940a9ff8f1d9 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -33,7 +33,6 @@ impl OutputFormatter for JunitFormatter { _shuffle_seed: Option, ) -> io::Result<()> { // We write xml header on run start - self.out.write_all(b"\n")?; self.write_message("") } @@ -138,7 +137,7 @@ impl OutputFormatter for JunitFormatter { self.write_message("")?; self.write_message("")?; - self.out.write_all(b"\n\n")?; + self.out.write_all(b"\n")?; Ok(state.failed == 0) } From 3b52ccaa951240faf90e963ee2f5188085b6fb82 Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Wed, 2 Feb 2022 19:28:01 -0500 Subject: [PATCH 7/7] Correct incorrect description of preorder traversals. --- compiler/rustc_middle/src/mir/traversal.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 8c930fd161efb..480f28620dc8f 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -4,8 +4,9 @@ use super::*; /// Preorder traversal of a graph. /// -/// Preorder traversal is when each node is visited before any of its -/// successors +/// Preorder traversal is when each node is visited after at least one of its predecessors. If you +/// are familar with some basic graph theory, then this performs a depth first search and returns +/// nodes in order of discovery time. /// /// ```text /// @@ -82,8 +83,9 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { /// Postorder traversal of a graph. /// -/// Postorder traversal is when each node is visited after all of its -/// successors, except when the successor is only reachable by a back-edge +/// Postorder traversal is when each node is visited after all of its successors, except when the +/// 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