about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs76
-rw-r--r--compiler/rustc_ast_pretty/src/pp/convenience.rs77
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs30
-rw-r--r--compiler/rustc_driver/src/lib.rs51
-rw-r--r--compiler/rustc_middle/src/mir/traversal.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs2
-rw-r--r--library/test/src/formatters/junit.rs3
-rw-r--r--src/test/ui/consts/recursive.rs11
-rw-r--r--src/test/ui/consts/recursive.stderr31
-rw-r--r--src/test/ui/panics/default-backtrace-ice.rs9
-rw-r--r--src/test/ui/panics/default-backtrace-ice.stderr18
12 files changed, 215 insertions, 105 deletions
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index 26d600cefc7..d567c8dae43 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<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 })
-    }
 }
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 00000000000..1b9ac705883
--- /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<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 }))
+    }
+}
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 87298023980..89a0f8245e5 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 0f490c33102..acf221a08ee 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<as
 /// debugging, since some ICEs only happens with non-default compiler flags
 /// (and the users don't always report them).
 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 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 8c930fd161e..480f28620dc 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 6329bcee4fa..a4e100973b6 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 283eda7c85e..c95dff13d66 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<K: DepKind> EncoderState<K> {
             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 fa23cf26896..f940a9ff8f1 100644
--- a/library/test/src/formatters/junit.rs
+++ b/library/test/src/formatters/junit.rs
@@ -33,7 +33,6 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
         _shuffle_seed: Option<u64>,
     ) -> io::Result<()> {
         // We write xml header on run start
-        self.out.write_all(b"\n")?;
         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("</testsuites>")?;
 
-        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 00000000000..664940c52cf
--- /dev/null
+++ b/src/test/ui/consts/recursive.rs
@@ -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() {}
diff --git a/src/test/ui/consts/recursive.stderr b/src/test/ui/consts/recursive.stderr
new file mode 100644
index 00000000000..31ac1fff4e8
--- /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<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
+
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 00000000000..fd86a3f9dfa
--- /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 00000000000..a0025d7e221
--- /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