mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
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:
commit
4e8fb743cc
@ -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 })
|
||||
}
|
||||
}
|
||||
|
77
compiler/rustc_ast_pretty/src/pp/convenience.rs
Normal file
77
compiler/rustc_ast_pretty/src/pp/convenience.rs
Normal 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 }))
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
11
src/test/ui/consts/recursive.rs
Normal file
11
src/test/ui/consts/recursive.rs
Normal 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() {}
|
31
src/test/ui/consts/recursive.stderr
Normal file
31
src/test/ui/consts/recursive.stderr
Normal 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
|
||||
|
9
src/test/ui/panics/default-backtrace-ice.rs
Normal file
9
src/test/ui/panics/default-backtrace-ice.rs
Normal 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; }
|
18
src/test/ui/panics/default-backtrace-ice.stderr
Normal file
18
src/test/ui/panics/default-backtrace-ice.stderr
Normal 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
|
Loading…
Reference in New Issue
Block a user