diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 26d600cefc7c0..d567c8dae43a4 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; @@ -186,12 +187,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, @@ -441,73 +436,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 })) + } +} 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/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 0f490c3310245..acf221a08eeb2 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -66,7 +66,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"]; @@ -1100,31 +1100,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), + } } } } @@ -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/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 diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6329bcee4fa3f..a4e100973b675 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), } } 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) } 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 + 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