From 59df6c8eb917cba41c15e3366f29ee780c9c74df Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 22 Oct 2021 12:21:10 -0500 Subject: [PATCH 01/31] Try commiting again --- library/std/src/error.rs | 245 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 1 deletion(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 6ae0bc47a9462..9fb8f2b9b8bc5 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -25,7 +25,7 @@ use crate::backtrace::Backtrace; use crate::borrow::Cow; use crate::cell; use crate::char; -use crate::fmt::{self, Debug, Display}; +use crate::fmt::{self, Debug, Display, Write}; use crate::mem::transmute; use crate::num; use crate::str; @@ -807,3 +807,246 @@ impl dyn Error + Send + Sync { }) } } + +/// An error reporter that exposes the entire error chain for printing. +/// It also exposes options for formatting the error chain, either entirely on a single line, +/// or in multi-line format with each cause in the error chain on a new line. +/// +/// # Examples +/// +/// ``` +/// #![feature(error_reporter)] +/// +/// use std::error::{Error, Report}; +/// use std::fmt; +/// +/// #[derive(Debug)] +/// struct SuperError { +/// side: SuperErrorSideKick, +/// } +/// +/// impl fmt::Display for SuperError { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "SuperError is here!") +/// } +/// } +/// +/// impl Error for SuperError { +/// fn source(&self) -> Option<&(dyn Error + 'static)> { +/// Some(&self.side) +/// } +/// } +/// +/// #[derive(Debug)] +/// struct SuperErrorSideKick; +/// +/// impl fmt::Display for SuperErrorSideKick { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "SuperErrorSideKick is here!") +/// } +/// } +/// +/// impl Error for SuperErrorSideKick {} +/// +/// fn main() { +/// let error = SuperError { side: SuperErrorSideKick }; +/// let report = Report::new(&error).pretty(); +/// +/// println!("{}", report); +/// } +/// ``` +#[unstable(feature = "error_reporter", issue = "90172")] +pub struct Report { + source: E, + show_backtrace: bool, + pretty: bool, +} + +impl Report +where + E: Error, +{ + /// Create a new `Report` from an input error. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn new(source: E) -> Report { + Report { source, show_backtrace: false, pretty: false } + } + + /// Enable pretty-printing the report. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn pretty(mut self) -> Self { + self.pretty = true; + self + } + + /// Enable showing a backtrace for the report. + #[unstable(feature = "error_reporter", issue = "90172")] + pub fn show_backtrace(mut self) -> Self { + self.show_backtrace = true; + self + } + + /// Format the report as a single line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.source)?; + + let sources = self.source.source().into_iter().flat_map(::chain); + + for cause in sources { + write!(f, ": {}", cause)?; + } + + Ok(()) + } + + /// Format the report as multiple lines, with each error cause on its own line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let error = &self.source; + + write!(f, "{}", error)?; + + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; + + let multiple = cause.source().is_some(); + let format = if multiple { + Format::Numbered { ind: 0 } + } else { + Format::Uniform { indentation: " " } + }; + + for error in cause.chain() { + writeln!(f)?; + + let mut indented = Indented { inner: f, needs_indent: true, format }; + + write!(indented, "{}", error)?; + } + } + + if self.show_backtrace { + let backtrace = error.backtrace(); + + if let Some(backtrace) = backtrace { + let mut backtrace = backtrace.to_string(); + + write!(f, "\n\n")?; + writeln!(f, "Stack backtrace:")?; + + backtrace.truncate(backtrace.trim_end().len()); + + write!(f, "{}", backtrace)?; + } + } + + Ok(()) + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl From for Report +where + E: Error, +{ + fn from(source: E) -> Self { + Report::new(source) + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Display for Report +where + E: Error, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } + } +} + +// This type intentionally outputs the same format for `Display` and `Debug`for +// situations where you unwrap a `Report` or return it from main. +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Debug for Report +where + E: Error, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +/// Encapsulates how error sources are indented and formatted. +struct Indented<'a, D: ?Sized> { + inner: &'a mut D, + needs_indent: bool, + format: Format, +} + +/// The possible variants that error sources can be formatted as. +#[derive(Clone, Copy)] +enum Format { + /// Insert uniform indentation before every line. + /// + /// This format takes a static string as input and inserts it after every newline. + Uniform { + /// The string to insert as indentation. + indentation: &'static str, + }, + /// Inserts a number before the first line. + /// + /// This format hard codes the indentation level to match the indentation from + /// `std::backtrace::Backtrace`. + Numbered { + /// The index to insert before the first line of output. + ind: usize, + }, +} + +impl Write for Indented<'_, D> +where + D: Write + ?Sized, +{ + fn write_str(&mut self, s: &str) -> fmt::Result { + for (ind, line) in s.split('\n').enumerate() { + if ind > 0 { + self.inner.write_char('\n')?; + self.needs_indent = true; + } + + if self.needs_indent { + if line.is_empty() { + continue; + } + + self.format.insert_indentation(ind, &mut self.inner)?; + self.needs_indent = false; + } + + self.inner.write_fmt(format_args!("{}", line))?; + } + + Ok(()) + } +} + +impl Format { + /// Write the specified formatting to the write buffer. + fn insert_indentation(&mut self, line: usize, f: &mut dyn Write) -> fmt::Result { + match self { + Format::Uniform { indentation } => { + write!(f, "{}", indentation) + } + Format::Numbered { ind } => { + if line == 0 { + write!(f, "{: >4}: ", ind)?; + *ind += 1; + Ok(()) + } else { + write!(f, " ") + } + } + } + } +} From 6a59d0e3aa26543fc4d3eaae1fa4cd48522045d2 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 22 Oct 2021 13:43:42 -0500 Subject: [PATCH 02/31] Have `pretty` and `show_backtrace` accept booleans --- library/std/src/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 9fb8f2b9b8bc5..5988075836d54 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -850,7 +850,7 @@ impl dyn Error + Send + Sync { /// /// fn main() { /// let error = SuperError { side: SuperErrorSideKick }; -/// let report = Report::new(&error).pretty(); +/// let report = Report::new(&error).pretty(true); /// /// println!("{}", report); /// } @@ -874,15 +874,15 @@ where /// Enable pretty-printing the report. #[unstable(feature = "error_reporter", issue = "90172")] - pub fn pretty(mut self) -> Self { - self.pretty = true; + pub fn pretty(mut self, pretty: bool) -> Self { + self.pretty = pretty; self } /// Enable showing a backtrace for the report. #[unstable(feature = "error_reporter", issue = "90172")] - pub fn show_backtrace(mut self) -> Self { - self.show_backtrace = true; + pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { + self.show_backtrace = show_backtrace; self } From c6de41331c732a8f70088ceab12a5049e3db0caa Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Fri, 22 Oct 2021 13:47:05 -0500 Subject: [PATCH 03/31] Change `source` field to `error` --- library/std/src/error.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 5988075836d54..52f3ebbdee47e 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -857,7 +857,7 @@ impl dyn Error + Send + Sync { /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { - source: E, + error: E, show_backtrace: bool, pretty: bool, } @@ -868,8 +868,8 @@ where { /// Create a new `Report` from an input error. #[unstable(feature = "error_reporter", issue = "90172")] - pub fn new(source: E) -> Report { - Report { source, show_backtrace: false, pretty: false } + pub fn new(error: E) -> Report { + Report { error, show_backtrace: false, pretty: false } } /// Enable pretty-printing the report. @@ -889,9 +889,9 @@ where /// Format the report as a single line. #[unstable(feature = "error_reporter", issue = "90172")] fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.source)?; + write!(f, "{}", self.error)?; - let sources = self.source.source().into_iter().flat_map(::chain); + let sources = self.error.source().into_iter().flat_map(::chain); for cause in sources { write!(f, ": {}", cause)?; @@ -903,7 +903,7 @@ where /// Format the report as multiple lines, with each error cause on its own line. #[unstable(feature = "error_reporter", issue = "90172")] fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let error = &self.source; + let error = &self.error; write!(f, "{}", error)?; @@ -950,8 +950,8 @@ impl From for Report where E: Error, { - fn from(source: E) -> Self { - Report::new(source) + fn from(error: E) -> Self { + Report::new(error) } } From c0f14cb9301eacb51fc660f1d461cbc783f4aaa7 Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:03:53 -0500 Subject: [PATCH 04/31] Attempt to fix tidy errors --- library/std/src/error.rs | 133 ++++++--------- library/std/src/error/tests.rs | 291 +++++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+), 79 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 52f3ebbdee47e..d8859cf1e552e 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -25,7 +25,7 @@ use crate::backtrace::Backtrace; use crate::borrow::Cow; use crate::cell; use crate::char; -use crate::fmt::{self, Debug, Display, Write}; +use crate::fmt::{self, Debug, Display}; use crate::mem::transmute; use crate::num; use crate::str; @@ -816,6 +816,7 @@ impl dyn Error + Send + Sync { /// /// ``` /// #![feature(error_reporter)] +/// #![feature(negative_impls)] /// /// use std::error::{Error, Report}; /// use std::fmt; @@ -848,6 +849,10 @@ impl dyn Error + Send + Sync { /// /// impl Error for SuperErrorSideKick {} /// +/// // Note that the error doesn't need to be `Send` or `Sync`. +/// impl !Send for SuperError {} +/// impl !Sync for SuperError {} +/// /// fn main() { /// let error = SuperError { side: SuperErrorSideKick }; /// let report = Report::new(&error).pretty(true); @@ -855,10 +860,37 @@ impl dyn Error + Send + Sync { /// println!("{}", report); /// } /// ``` +/// +/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the +/// wrapped error be `Send`, `Sync`, or `'static`. +/// +/// ```rust +/// # #![feature(error_reporter)] +/// # use std::fmt; +/// # use std::error::{Error, Report}; +/// #[derive(Debug)] +/// struct SuperError<'a> { +/// side: &'a str, +/// } +/// impl<'a> fmt::Display for SuperError<'a> { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "SuperError is here: {}", self.side) +/// } +/// } +/// impl<'a> Error for SuperError<'a> {} +/// fn main() { +/// let msg = String::from("Huzzah!"); +/// let report = Report::new(SuperError { side: &msg }); +/// println!("{}", report); +/// } +/// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { + /// The error being reported. error: E, + /// Whether a backtrace should be included as part of the report. show_backtrace: bool, + /// Whether the report should be pretty-printed. pretty: bool, } @@ -911,18 +943,15 @@ where write!(f, "\n\nCaused by:")?; let multiple = cause.source().is_some(); - let format = if multiple { - Format::Numbered { ind: 0 } - } else { - Format::Uniform { indentation: " " } - }; - for error in cause.chain() { + for (ind, error) in cause.chain().enumerate() { writeln!(f)?; - let mut indented = Indented { inner: f, needs_indent: true, format }; - - write!(indented, "{}", error)?; + if multiple { + write!(f, "{: >4}: {}", ind, Indented { source: error })?; + } else { + write!(f, " {}", error)?; + } } } @@ -930,14 +959,10 @@ where let backtrace = error.backtrace(); if let Some(backtrace) = backtrace { - let mut backtrace = backtrace.to_string(); - - write!(f, "\n\n")?; - writeln!(f, "Stack backtrace:")?; + let backtrace = backtrace.to_string(); - backtrace.truncate(backtrace.trim_end().len()); - - write!(f, "{}", backtrace)?; + f.write_str("\n\nStack backtrace:\n")?; + f.write_str(backtrace.trim_end())?; } } @@ -977,76 +1002,26 @@ where } } -/// Encapsulates how error sources are indented and formatted. -struct Indented<'a, D: ?Sized> { - inner: &'a mut D, - needs_indent: bool, - format: Format, -} - -/// The possible variants that error sources can be formatted as. -#[derive(Clone, Copy)] -enum Format { - /// Insert uniform indentation before every line. - /// - /// This format takes a static string as input and inserts it after every newline. - Uniform { - /// The string to insert as indentation. - indentation: &'static str, - }, - /// Inserts a number before the first line. - /// - /// This format hard codes the indentation level to match the indentation from - /// `std::backtrace::Backtrace`. - Numbered { - /// The index to insert before the first line of output. - ind: usize, - }, +/// Wrapper type for indenting the inner source. +struct Indented { + source: D, } -impl Write for Indented<'_, D> +impl fmt::Display for Indented where - D: Write + ?Sized, + D: fmt::Display, { - fn write_str(&mut self, s: &str) -> fmt::Result { - for (ind, line) in s.split('\n').enumerate() { - if ind > 0 { - self.inner.write_char('\n')?; - self.needs_indent = true; - } - - if self.needs_indent { - if line.is_empty() { - continue; - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let source = self.source.to_string(); - self.format.insert_indentation(ind, &mut self.inner)?; - self.needs_indent = false; + for (ind, line) in source.trim().split('\n').filter(|l| !l.is_empty()).enumerate() { + if ind > 0 { + write!(f, "\n {}", line)?; + } else { + write!(f, "{}", line)?; } - - self.inner.write_fmt(format_args!("{}", line))?; } Ok(()) } } - -impl Format { - /// Write the specified formatting to the write buffer. - fn insert_indentation(&mut self, line: usize, f: &mut dyn Write) -> fmt::Result { - match self { - Format::Uniform { indentation } => { - write!(f, "{}", indentation) - } - Format::Numbered { ind } => { - if line == 0 { - write!(f, "{: >4}: ", ind)?; - *ind += 1; - Ok(()) - } else { - write!(f, " ") - } - } - } - } -} diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index 66d6924f34d2b..c408915ca71a9 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -35,3 +35,294 @@ fn downcasting() { Err(e) => assert_eq!(*e.downcast::().unwrap(), A), } } + +use crate::backtrace; +use crate::env; +use crate::error::Report; + +#[derive(Debug)] +struct SuperError { + side: SuperErrorSideKick, +} + +impl fmt::Display for SuperError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SuperError is here!") + } +} + +impl Error for SuperError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + Some(&self.side) + } +} + +#[derive(Debug)] +struct SuperErrorSideKick; + +impl fmt::Display for SuperErrorSideKick { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SuperErrorSideKick is here!") + } +} + +impl Error for SuperErrorSideKick {} + +#[test] +fn single_line_formatting() { + let error = SuperError { side: SuperErrorSideKick }; + let report = Report::new(&error); + let actual = report.to_string(); + let expected = String::from("SuperError is here!: SuperErrorSideKick is here!"); + + assert_eq!(expected, actual); +} + +#[test] +fn multi_line_formatting() { + let error = SuperError { side: SuperErrorSideKick }; + let report = Report::new(&error).pretty(true); + let actual = report.to_string(); + let expected = + String::from("SuperError is here!\n\nCaused by:\n SuperErrorSideKick is here!"); + + assert_eq!(expected, actual); +} + +#[test] +fn error_with_no_sources_formats_single_line_correctly() { + let report = Report::new(SuperErrorSideKick); + let actual = report.to_string(); + let expected = String::from("SuperErrorSideKick is here!"); + + assert_eq!(expected, actual); +} + +#[test] +fn error_with_no_sources_formats_multi_line_correctly() { + let report = Report::new(SuperErrorSideKick).pretty(true); + let actual = report.to_string(); + let expected = String::from("SuperErrorSideKick is here!"); + + assert_eq!(expected, actual); +} + +#[test] +fn error_with_backtrace_outputs_correctly() { + use backtrace::Backtrace; + + env::remove_var("RUST_BACKTRACE"); + + #[derive(Debug)] + struct ErrorWithBacktrace<'a> { + msg: &'a str, + trace: Backtrace, + } + + impl<'a> fmt::Display for ErrorWithBacktrace<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Error with backtrace: {}", self.msg) + } + } + + impl<'a> Error for ErrorWithBacktrace<'a> { + fn backtrace(&self) -> Option<&Backtrace> { + Some(&self.trace) + } + } + + let msg = String::from("The source of the error"); + let report = Report::new(ErrorWithBacktrace { msg: &msg, trace: Backtrace::capture() }) + .pretty(true) + .show_backtrace(true); + + let expected = String::from( + "Error with backtrace: The source of the error\n\nStack backtrace:\ndisabled backtrace", + ); + + assert_eq!(expected, report.to_string()); +} + +#[derive(Debug)] +struct GenericError { + message: D, + source: Option>, +} + +impl GenericError { + fn new(message: D) -> GenericError { + Self { message, source: None } + } + + fn new_with_source(message: D, source: E) -> GenericError + where + E: Error + 'static, + { + let source: Box = Box::new(source); + let source = Some(source); + GenericError { message, source } + } +} + +impl fmt::Display for GenericError +where + D: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.message, f) + } +} + +impl Error for GenericError +where + D: fmt::Debug + fmt::Display, +{ + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.source.as_deref() + } +} + +#[test] +fn error_formats_single_line_with_rude_display_impl() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("line 1\nline 2")?; + f.write_str("\nline 3\nline 4\n")?; + f.write_str("line 5\nline 6")?; + Ok(()) + } + } + + let error = GenericError::new(MyMessage); + let error = GenericError::new_with_source(MyMessage, error); + let error = GenericError::new_with_source(MyMessage, error); + let error = GenericError::new_with_source(MyMessage, error); + let report = Report::new(error); + let expected = r#"line 1 +line 2 +line 3 +line 4 +line 5 +line 6: line 1 +line 2 +line 3 +line 4 +line 5 +line 6: line 1 +line 2 +line 3 +line 4 +line 5 +line 6: line 1 +line 2 +line 3 +line 4 +line 5 +line 6"#; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} + +#[test] +fn error_formats_multi_line_with_rude_display_impl() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("line 1\nline 2")?; + f.write_str("\nline 3\nline 4\n")?; + f.write_str("line 5\nline 6")?; + Ok(()) + } + } + + let error = GenericError::new(MyMessage); + let error = GenericError::new_with_source(MyMessage, error); + let error = GenericError::new_with_source(MyMessage, error); + let error = GenericError::new_with_source(MyMessage, error); + let report = Report::new(error).pretty(true); + let expected = r#"line 1 +line 2 +line 3 +line 4 +line 5 +line 6 + +Caused by: + 0: line 1 + line 2 + line 3 + line 4 + line 5 + line 6 + 1: line 1 + line 2 + line 3 + line 4 + line 5 + line 6 + 2: line 1 + line 2 + line 3 + line 4 + line 5 + line 6"#; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} + +#[test] +fn errors_that_start_with_newline_formats_correctly() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("\nThe message\n") + } + } + + let error = GenericError::new(MyMessage); + let error = GenericError::new_with_source(MyMessage, error); + let error = GenericError::new_with_source(MyMessage, error); + let report = Report::new(error).pretty(true); + let expected = r#" +The message + + +Caused by: + 0: The message + 1: The message"#; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} + +#[test] +fn errors_with_string_interpolation_formats_correctly() { + #[derive(Debug)] + struct MyMessage(usize); + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Got an error code: ({}). ", self.0)?; + write!(f, "What would you like to do in response?") + } + } + + let error = GenericError::new(MyMessage(10)); + let error = GenericError::new_with_source(MyMessage(20), error); + let report = Report::new(error).pretty(true); + let expected = r#"Got an error code: (20). What would you like to do in response? + +Caused by: + Got an error code: (10). What would you like to do in response?"#; + let actual = report.to_string(); + assert_eq!(expected, actual); +} From aa853bd31775db7fcb5074f78d8b989053ae101d Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:04:42 -0500 Subject: [PATCH 05/31] Add `rust` annotation to doctest --- library/std/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index d8859cf1e552e..a6d36dbe5c794 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -814,7 +814,7 @@ impl dyn Error + Send + Sync { /// /// # Examples /// -/// ``` +/// ```rust /// #![feature(error_reporter)] /// #![feature(negative_impls)] /// From d2f49eeb176a670c76f3c8c6005208a9d3cc30ee Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:18:22 -0500 Subject: [PATCH 06/31] Format doctest --- library/std/src/error.rs | 55 ++++++++-------------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index a6d36dbe5c794..26fa6c38549d3 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -811,6 +811,8 @@ impl dyn Error + Send + Sync { /// An error reporter that exposes the entire error chain for printing. /// It also exposes options for formatting the error chain, either entirely on a single line, /// or in multi-line format with each cause in the error chain on a new line. +/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the +/// wrapped error be `Send`, `Sync`, or `'static`. /// /// # Examples /// @@ -822,68 +824,31 @@ impl dyn Error + Send + Sync { /// use std::fmt; /// /// #[derive(Debug)] -/// struct SuperError { -/// side: SuperErrorSideKick, -/// } -/// -/// impl fmt::Display for SuperError { -/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperError is here!") -/// } -/// } -/// -/// impl Error for SuperError { -/// fn source(&self) -> Option<&(dyn Error + 'static)> { -/// Some(&self.side) -/// } +/// struct SuperError<'a> { +/// side: &'a str, /// } /// -/// #[derive(Debug)] -/// struct SuperErrorSideKick; -/// -/// impl fmt::Display for SuperErrorSideKick { +/// impl<'a> fmt::Display for SuperError<'a> { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperErrorSideKick is here!") +/// write!(f, "SuperError is here: {}", self.side) /// } /// } /// -/// impl Error for SuperErrorSideKick {} +/// impl<'a> Error for SuperError<'a> {} /// /// // Note that the error doesn't need to be `Send` or `Sync`. /// impl !Send for SuperError {} /// impl !Sync for SuperError {} /// /// fn main() { -/// let error = SuperError { side: SuperErrorSideKick }; +/// let msg = String::from("Huzzah!"); +/// let error = SuperError { side: &msg }; /// let report = Report::new(&error).pretty(true); /// /// println!("{}", report); /// } /// ``` -/// -/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the -/// wrapped error be `Send`, `Sync`, or `'static`. -/// -/// ```rust -/// # #![feature(error_reporter)] -/// # use std::fmt; -/// # use std::error::{Error, Report}; -/// #[derive(Debug)] -/// struct SuperError<'a> { -/// side: &'a str, -/// } -/// impl<'a> fmt::Display for SuperError<'a> { -/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperError is here: {}", self.side) -/// } -/// } -/// impl<'a> Error for SuperError<'a> {} -/// fn main() { -/// let msg = String::from("Huzzah!"); -/// let report = Report::new(SuperError { side: &msg }); -/// println!("{}", report); -/// } -/// ``` + #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { /// The error being reported. From 32bcb8113f750db36b9590b516a9fc40c0fa99df Mon Sep 17 00:00:00 2001 From: Sean Chen Date: Wed, 27 Oct 2021 13:59:02 -0500 Subject: [PATCH 07/31] Fix broken doctest --- library/std/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 26fa6c38549d3..b45cfa3450684 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -837,8 +837,8 @@ impl dyn Error + Send + Sync { /// impl<'a> Error for SuperError<'a> {} /// /// // Note that the error doesn't need to be `Send` or `Sync`. -/// impl !Send for SuperError {} -/// impl !Sync for SuperError {} +/// impl<'a> !Send for SuperError<'a> {} +/// impl<'a> !Sync for SuperError<'a> {} /// /// fn main() { /// let msg = String::from("Huzzah!"); From 1386a15529f5241402125b37eda7a5bb03fbd247 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Tue, 14 Dec 2021 13:56:49 -0800 Subject: [PATCH 08/31] Update std::error::Report based on feedback --- library/std/src/error.rs | 74 +++++++++----- library/std/src/error/tests.rs | 178 +++++++++++++++++++++++---------- 2 files changed, 171 insertions(+), 81 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index b45cfa3450684..10de248c3d7ec 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -25,7 +25,7 @@ use crate::backtrace::Backtrace; use crate::borrow::Cow; use crate::cell; use crate::char; -use crate::fmt::{self, Debug, Display}; +use crate::fmt::{self, Debug, Display, Write}; use crate::mem::transmute; use crate::num; use crate::str; @@ -63,7 +63,7 @@ pub trait Error: Debug + Display { /// /// #[derive(Debug)] /// struct SuperError { - /// side: SuperErrorSideKick, + /// source: SuperErrorSideKick, /// } /// /// impl fmt::Display for SuperError { @@ -74,7 +74,7 @@ pub trait Error: Debug + Display { /// /// impl Error for SuperError { /// fn source(&self) -> Option<&(dyn Error + 'static)> { - /// Some(&self.side) + /// Some(&self.source) /// } /// } /// @@ -90,7 +90,7 @@ pub trait Error: Debug + Display { /// impl Error for SuperErrorSideKick {} /// /// fn get_super_error() -> Result<(), SuperError> { - /// Err(SuperError { side: SuperErrorSideKick }) + /// Err(SuperError { source: SuperErrorSideKick }) /// } /// /// fn main() { @@ -836,10 +836,6 @@ impl dyn Error + Send + Sync { /// /// impl<'a> Error for SuperError<'a> {} /// -/// // Note that the error doesn't need to be `Send` or `Sync`. -/// impl<'a> !Send for SuperError<'a> {} -/// impl<'a> !Sync for SuperError<'a> {} -/// /// fn main() { /// let msg = String::from("Huzzah!"); /// let error = SuperError { side: &msg }; @@ -883,6 +879,19 @@ where self } + fn backtrace(&self) -> Option<&Backtrace> { + // have to grab the backtrace on the first error directly since that error may not be + // 'static + let backtrace = self.error.backtrace(); + let backtrace = backtrace.or_else(|| { + self.error + .source() + .map(|source| source.chain().find_map(|source| source.backtrace())) + .flatten() + }); + backtrace + } + /// Format the report as a single line. #[unstable(feature = "error_reporter", issue = "90172")] fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -911,17 +920,17 @@ where for (ind, error) in cause.chain().enumerate() { writeln!(f)?; - - if multiple { - write!(f, "{: >4}: {}", ind, Indented { source: error })?; - } else { - write!(f, " {}", error)?; - } + let mut indented = Indented { + inner: f, + number: if multiple { Some(ind) } else { None }, + started: false, + }; + write!(indented, "{}", error)?; } } if self.show_backtrace { - let backtrace = error.backtrace(); + let backtrace = self.backtrace(); if let Some(backtrace) = backtrace { let backtrace = backtrace.to_string(); @@ -968,23 +977,34 @@ where } /// Wrapper type for indenting the inner source. -struct Indented { - source: D, +struct Indented<'a, D> { + inner: &'a mut D, + number: Option, + started: bool, } -impl fmt::Display for Indented +impl Write for Indented<'_, T> where - D: fmt::Display, + T: Write, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let source = self.source.to_string(); - - for (ind, line) in source.trim().split('\n').filter(|l| !l.is_empty()).enumerate() { - if ind > 0 { - write!(f, "\n {}", line)?; - } else { - write!(f, "{}", line)?; + fn write_str(&mut self, s: &str) -> fmt::Result { + for (i, line) in s.split('\n').enumerate() { + if !self.started { + self.started = true; + match self.number { + Some(number) => write!(self.inner, "{: >5}: ", number)?, + None => self.inner.write_str(" ")?, + } + } else if i > 0 { + self.inner.write_char('\n')?; + if self.number.is_some() { + self.inner.write_str(" ")?; + } else { + self.inner.write_str(" ")?; + } } + + self.inner.write_str(line)?; } Ok(()) diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index c408915ca71a9..82ef39ae90fb6 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -36,13 +36,12 @@ fn downcasting() { } } -use crate::backtrace; -use crate::env; +use crate::backtrace::Backtrace; use crate::error::Report; #[derive(Debug)] struct SuperError { - side: SuperErrorSideKick, + source: SuperErrorSideKick, } impl fmt::Display for SuperError { @@ -53,7 +52,7 @@ impl fmt::Display for SuperError { impl Error for SuperError { fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(&self.side) + Some(&self.source) } } @@ -70,7 +69,7 @@ impl Error for SuperErrorSideKick {} #[test] fn single_line_formatting() { - let error = SuperError { side: SuperErrorSideKick }; + let error = SuperError { source: SuperErrorSideKick }; let report = Report::new(&error); let actual = report.to_string(); let expected = String::from("SuperError is here!: SuperErrorSideKick is here!"); @@ -80,7 +79,7 @@ fn single_line_formatting() { #[test] fn multi_line_formatting() { - let error = SuperError { side: SuperErrorSideKick }; + let error = SuperError { source: SuperErrorSideKick }; let report = Report::new(&error).pretty(true); let actual = report.to_string(); let expected = @@ -108,50 +107,57 @@ fn error_with_no_sources_formats_multi_line_correctly() { } #[test] -fn error_with_backtrace_outputs_correctly() { - use backtrace::Backtrace; +fn error_with_backtrace_outputs_correctly_with_one_source() { + let trace = Backtrace::force_capture(); + let expected = format!("The source of the error - env::remove_var("RUST_BACKTRACE"); +Caused by: + Error with backtrace - #[derive(Debug)] - struct ErrorWithBacktrace<'a> { - msg: &'a str, - trace: Backtrace, - } +Stack backtrace: +{}", trace); + let error = GenericError::new("Error with backtrace"); + let mut error = GenericError::new_with_source("The source of the error", error); + error.backtrace = Some(trace); + let report = Report::new(error).pretty(true).show_backtrace(true); - impl<'a> fmt::Display for ErrorWithBacktrace<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Error with backtrace: {}", self.msg) - } - } - impl<'a> Error for ErrorWithBacktrace<'a> { - fn backtrace(&self) -> Option<&Backtrace> { - Some(&self.trace) - } - } + println!("Error: {}", report); + assert_eq!(expected.trim_end(), report.to_string()); +} + +#[test] +fn error_with_backtrace_outputs_correctly_with_two_sources() { + let trace = Backtrace::force_capture(); + let expected = format!("Error with two sources - let msg = String::from("The source of the error"); - let report = Report::new(ErrorWithBacktrace { msg: &msg, trace: Backtrace::capture() }) - .pretty(true) - .show_backtrace(true); +Caused by: + 0: The source of the error + 1: Error with backtrace - let expected = String::from( - "Error with backtrace: The source of the error\n\nStack backtrace:\ndisabled backtrace", - ); +Stack backtrace: +{}", trace); + let mut error = GenericError::new("Error with backtrace"); + error.backtrace = Some(trace); + let error = GenericError::new_with_source("The source of the error", error); + let error = GenericError::new_with_source("Error with two sources", error); + let report = Report::new(error).pretty(true).show_backtrace(true); - assert_eq!(expected, report.to_string()); + + println!("Error: {}", report); + assert_eq!(expected.trim_end(), report.to_string()); } #[derive(Debug)] struct GenericError { message: D, + backtrace: Option, source: Option>, } impl GenericError { fn new(message: D) -> GenericError { - Self { message, source: None } + Self { message, backtrace: None, source: None } } fn new_with_source(message: D, source: E) -> GenericError @@ -160,7 +166,7 @@ impl GenericError { { let source: Box = Box::new(source); let source = Some(source); - GenericError { message, source } + GenericError { message, backtrace: None, source } } } @@ -180,6 +186,10 @@ where fn source(&self) -> Option<&(dyn Error + 'static)> { self.source.as_deref() } + + fn backtrace(&self) -> Option<&Backtrace> { + self.backtrace.as_ref() + } } #[test] @@ -254,24 +264,24 @@ line 5 line 6 Caused by: - 0: line 1 - line 2 - line 3 - line 4 - line 5 - line 6 - 1: line 1 - line 2 - line 3 - line 4 - line 5 - line 6 - 2: line 1 - line 2 - line 3 - line 4 - line 5 - line 6"#; + 0: line 1 + line 2 + line 3 + line 4 + line 5 + line 6 + 1: line 1 + line 2 + line 3 + line 4 + line 5 + line 6 + 2: line 1 + line 2 + line 3 + line 4 + line 5 + line 6"#; let actual = report.to_string(); assert_eq!(expected, actual); @@ -297,8 +307,12 @@ The message Caused by: - 0: The message - 1: The message"#; + 0: + The message + + 1: + The message + "#; let actual = report.to_string(); assert_eq!(expected, actual); @@ -326,3 +340,59 @@ Caused by: let actual = report.to_string(); assert_eq!(expected, actual); } + +#[test] +fn empty_lines_mid_message() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("line 1\n\nline 2") + } + } + + let error = GenericError::new(MyMessage); + let error = GenericError::new_with_source(MyMessage, error); + let error = GenericError::new_with_source(MyMessage, error); + let report = Report::new(error).pretty(true); + let expected = r#"line 1 + +line 2 + +Caused by: + 0: line 1 + + line 2 + 1: line 1 + + line 2"#; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} + +#[test] +fn only_one_source() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("line 1\nline 2") + } + } + + let error = GenericError::new(MyMessage); + let error = GenericError::new_with_source(MyMessage, error); + let report = Report::new(error).pretty(true); + let expected = r#"line 1 +line 2 + +Caused by: + line 1 + line 2"#; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} From 689a868a1f6f20b49ea904ca7cda14636b7768b3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Dec 2021 15:17:16 +0000 Subject: [PATCH 09/31] Remove some noise from opaque type errors around associated types --- .../rustc_infer/src/infer/opaque_types.rs | 14 +++++ .../type-alias-impl-trait/bound_reduction2.rs | 4 -- .../bound_reduction2.stderr | 56 +------------------ 3 files changed, 17 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index c2ef0b41e27bf..eab5e5a5fb4e9 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -551,6 +551,20 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicate = predicate.subst(tcx, substs); debug!(?predicate); + // Replace all other mentions of the same opaque type with the hidden type, + // as the bounds must hold on the hidden type after all. + let predicate = predicate.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| match *ty.kind() { + ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { + ty_var + } + _ => ty, + }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }); + // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them. let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs index 579067340e85c..cee8186dd8f8c 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -15,9 +15,5 @@ impl Trait for () {} fn foo_desugared(_: T) -> Foo { //~^ ERROR non-defining opaque type use in defining scope - //~| ERROR non-defining opaque type use in defining scope - //~| ERROR non-defining opaque type use in defining scope - //~| ERROR `T` is part of concrete type but not used in parameter list - //~| ERROR `T` is part of concrete type but not used in parameter list () } diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index a77c0000f12e1..03e696fe89803 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,34 +1,8 @@ -error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/bound_reduction2.rs:16:60 - | -LL | fn foo_desugared(_: T) -> Foo { - | ____________________________________________________________^ -LL | | -LL | | -LL | | -... | -LL | | () -LL | | } - | |_^ - -error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/bound_reduction2.rs:16:60 - | -LL | fn foo_desugared(_: T) -> Foo { - | ____________________________________________________________^ -LL | | -LL | | -LL | | -... | -LL | | () -LL | | } - | |_^ - error: non-defining opaque type use in defining scope - --> $DIR/bound_reduction2.rs:16:1 + --> $DIR/bound_reduction2.rs:16:46 | LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | note: used non-generic type `::Assoc` for generic parameter --> $DIR/bound_reduction2.rs:9:10 @@ -36,35 +10,11 @@ note: used non-generic type `::Assoc` for generic parameter LL | type Foo = impl Trait; | ^ -error: non-defining opaque type use in defining scope - --> $DIR/bound_reduction2.rs:16:1 - | -LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: used non-generic type `_` for generic parameter - --> $DIR/bound_reduction2.rs:9:10 - | -LL | type Foo = impl Trait; - | ^ - -error: non-defining opaque type use in defining scope - --> $DIR/bound_reduction2.rs:16:1 - | -LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: used non-generic type `_` for generic parameter - --> $DIR/bound_reduction2.rs:9:10 - | -LL | type Foo = impl Trait; - | ^ - error: could not find defining uses --> $DIR/bound_reduction2.rs:9:15 | LL | type Foo = impl Trait; | ^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors From 5c4600227329a273c0c6c844e4a10ce650ead601 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Dec 2021 15:26:01 +0000 Subject: [PATCH 10/31] Eagerly instantiate opaque types --- compiler/rustc_infer/src/infer/opaque_types.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index eab5e5a5fb4e9..d5e65705b2885 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -551,14 +551,16 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let predicate = predicate.subst(tcx, substs); debug!(?predicate); - // Replace all other mentions of the same opaque type with the hidden type, - // as the bounds must hold on the hidden type after all. let predicate = predicate.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| match *ty.kind() { + // Replace all other mentions of the same opaque type with the hidden type, + // as the bounds must hold on the hidden type after all. ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { ty_var } + // Instantiate nested instances of `impl Trait`. + ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty), _ => ty, }, lt_op: |lt| lt, @@ -589,10 +591,6 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { return tcx.ty_error(); } } - // Change the predicate to refer to the type variable, - // which will be the concrete type instead of the opaque type. - // This also instantiates nested instances of `impl Trait`. - let predicate = self.instantiate_opaque_types_in_map(predicate); let cause = traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType); From bdeeb07bf6400622074f04ca2523dac1512ab662 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 16 Dec 2021 20:24:28 +0000 Subject: [PATCH 11/31] Prove obligations to termination instead of ignoring ambiguities. Sometimes an obligation depends on a later one, so we can't just process them in order like it was done previously. This is not a problem in our test suite, but there may be ICEs out there and it will definitely be a problem with lazy TAIT. --- .../src/traits/query/type_op/mod.rs | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 12ca3faeb3797..d662f61e2cf4d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -4,7 +4,9 @@ use crate::infer::canonical::{ use crate::infer::{InferCtxt, InferOk}; use crate::traits::query::Fallible; use crate::traits::ObligationCause; -use rustc_infer::infer::canonical::Canonical; +use rustc_infer::infer::canonical::{Canonical, Certainty}; +use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::PredicateObligations; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use std::fmt; @@ -17,7 +19,6 @@ pub mod implied_outlives_bounds; pub mod normalize; pub mod outlives; pub mod prove_predicate; -use self::prove_predicate::ProvePredicate; pub mod subtype; pub use rustc_middle::traits::query::type_op::*; @@ -80,9 +81,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { query_key: ParamEnvAnd<'tcx, Self>, infcx: &InferCtxt<'_, 'tcx>, output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, - ) -> Fallible<(Self::QueryResponse, Option>>)> { + ) -> Fallible<( + Self::QueryResponse, + Option>>, + PredicateObligations<'tcx>, + Certainty, + )> { if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { - return Ok((result, None)); + return Ok((result, None, vec![], Certainty::Proven)); } // FIXME(#33684) -- We need to use @@ -104,20 +110,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { output_query_region_constraints, )?; - // Typically, instantiating NLL query results does not - // create obligations. However, in some cases there - // are unresolved type variables, and unify them *can* - // create obligations. In that case, we have to go - // fulfill them. We do this via a (recursive) query. - for obligation in obligations { - let ((), _) = ProvePredicate::fully_perform_into( - obligation.param_env.and(ProvePredicate::new(obligation.predicate)), - infcx, - output_query_region_constraints, - )?; - } - - Ok((value, Some(canonical_self))) + Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty)) } } @@ -129,9 +122,39 @@ where fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible> { let mut region_constraints = QueryRegionConstraints::default(); - let (output, canonicalized_query) = + let (output, canonicalized_query, mut obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints)?; + // Typically, instantiating NLL query results does not + // create obligations. However, in some cases there + // are unresolved type variables, and unify them *can* + // create obligations. In that case, we have to go + // fulfill them. We do this via a (recursive) query. + while !obligations.is_empty() { + trace!("{:#?}", obligations); + let mut progress = false; + for obligation in std::mem::take(&mut obligations) { + let obligation = infcx.resolve_vars_if_possible(obligation); + match ProvePredicate::fully_perform_into( + obligation.param_env.and(ProvePredicate::new(obligation.predicate)), + infcx, + &mut region_constraints, + ) { + Ok(((), _, new, certainty)) => { + obligations.extend(new); + progress = true; + if let Certainty::Ambiguous = certainty { + obligations.push(obligation); + } + } + Err(_) => obligations.push(obligation), + } + } + if !progress { + return Err(NoSolution); + } + } + // Promote the final query-region-constraints into a // (optional) ref-counted vector: let region_constraints = From 4420cc33d6686c9d4ae6bf490b977fc47e56d340 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 14:06:28 -0800 Subject: [PATCH 12/31] Update report output and fix examples --- library/std/src/error.rs | 195 +++++++++++++++++++++++++++------ library/std/src/error/tests.rs | 132 ++++++++++++++-------- 2 files changed, 245 insertions(+), 82 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 10de248c3d7ec..a2b4eb2117dcc 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -808,9 +808,11 @@ impl dyn Error + Send + Sync { } } -/// An error reporter that exposes the entire error chain for printing. -/// It also exposes options for formatting the error chain, either entirely on a single line, -/// or in multi-line format with each cause in the error chain on a new line. +/// An error reporter that print's an error and its sources. +/// +/// Report also exposes configuration options for formatting the error chain, either entirely on a +/// single line, or in multi-line format with each cause in the error chain on a new line. +/// /// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the /// wrapped error be `Send`, `Sync`, or `'static`. /// @@ -818,33 +820,51 @@ impl dyn Error + Send + Sync { /// /// ```rust /// #![feature(error_reporter)] -/// #![feature(negative_impls)] -/// /// use std::error::{Error, Report}; /// use std::fmt; /// /// #[derive(Debug)] -/// struct SuperError<'a> { -/// side: &'a str, +/// struct SuperError { +/// source: SuperErrorSideKick, /// } /// -/// impl<'a> fmt::Display for SuperError<'a> { +/// impl fmt::Display for SuperError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// write!(f, "SuperError is here: {}", self.side) +/// write!(f, "SuperError is here!") /// } /// } /// -/// impl<'a> Error for SuperError<'a> {} +/// impl Error for SuperError { +/// fn source(&self) -> Option<&(dyn Error + 'static)> { +/// Some(&self.source) +/// } +/// } /// -/// fn main() { -/// let msg = String::from("Huzzah!"); -/// let error = SuperError { side: &msg }; -/// let report = Report::new(&error).pretty(true); +/// #[derive(Debug)] +/// struct SuperErrorSideKick; +/// +/// impl fmt::Display for SuperErrorSideKick { +/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// write!(f, "SuperErrorSideKick is here!") +/// } +/// } +/// +/// impl Error for SuperErrorSideKick {} /// -/// println!("{}", report); +/// fn get_super_error() -> Result<(), SuperError> { +/// Err(SuperError { source: SuperErrorSideKick }) +/// } +/// +/// fn main() { +/// match get_super_error() { +/// Err(e) => { +/// let report = Report::new(e).pretty(true); +/// println!("Error: {}", report); +/// } +/// _ => println!("No error"), +/// } /// } /// ``` - #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { /// The error being reported. @@ -865,14 +885,129 @@ where Report { error, show_backtrace: false, pretty: false } } - /// Enable pretty-printing the report. + /// Enable pretty-printing the report across multiple lines. + /// + /// # Examples + /// + /// ```rust + /// #![feature(error_reporter)] + /// use std::error::Report; + /// # use std::error::Error; + /// # use std::fmt; + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: SuperErrorSideKick, + /// # } + /// # impl fmt::Display for SuperError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperError is here!") + /// # } + /// # } + /// # impl Error for SuperError { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKick; + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKick {} + /// + /// let error = SuperError { source: SuperErrorSideKick }; + /// let report = Report::new(error).pretty(true); + /// eprintln!("Error: {:?}", report); + /// ``` + /// + /// This example produces the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// SuperErrorSideKick is here! + /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn pretty(mut self, pretty: bool) -> Self { self.pretty = pretty; self } - /// Enable showing a backtrace for the report. + /// Display backtrace if available when using pretty output format. + /// + /// # Examples + /// + /// ```rust + /// #![feature(error_reporter)] + /// #![feature(backtrace)] + /// use std::error::{Error, Report}; + /// use std::backtrace::Backtrace; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct SuperError { + /// source: SuperErrorSideKick, + /// } + /// + /// impl fmt::Display for SuperError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperError is here!") + /// } + /// } + /// + /// impl Error for SuperError { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// Some(&self.source) + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SuperErrorSideKick { + /// backtrace: Backtrace, + /// } + /// + /// impl fmt::Display for SuperErrorSideKick { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperErrorSideKick is here!") + /// } + /// } + /// + /// impl Error for SuperErrorSideKick { + /// fn backtrace(&self) -> Option<&Backtrace> { + /// Some(&self.backtrace) + /// } + /// } + /// + /// let source = SuperErrorSideKick { backtrace: Backtrace::force_capture() }; + /// let error = SuperError { source }; + /// let report = Report::new(error).pretty(true).show_backtrace(true); + /// eprintln!("Error: {:?}", report); + /// ``` + /// + /// This example produces something similar to the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// SuperErrorSideKick is here! + /// + /// Stack backtrace: + /// 0: rust_out::main::_doctest_main_src_error_rs_943_0 + /// 1: rust_out::main + /// 2: core::ops::function::FnOnce::call_once + /// 3: std::sys_common::backtrace::__rust_begin_short_backtrace + /// 4: std::rt::lang_start::{{closure}} + /// 5: std::panicking::try + /// 6: std::rt::lang_start_internal + /// 7: std::rt::lang_start + /// 8: main + /// 9: __libc_start_main + /// 10: _start + /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { self.show_backtrace = show_backtrace; @@ -922,10 +1057,12 @@ where writeln!(f)?; let mut indented = Indented { inner: f, - number: if multiple { Some(ind) } else { None }, - started: false, }; - write!(indented, "{}", error)?; + if multiple { + write!(indented, "{: >4}: {}", ind, error)?; + } else { + write!(indented, " {}", error)?; + } } } @@ -979,8 +1116,6 @@ where /// Wrapper type for indenting the inner source. struct Indented<'a, D> { inner: &'a mut D, - number: Option, - started: bool, } impl Write for Indented<'_, T> @@ -989,19 +1124,9 @@ where { fn write_str(&mut self, s: &str) -> fmt::Result { for (i, line) in s.split('\n').enumerate() { - if !self.started { - self.started = true; - match self.number { - Some(number) => write!(self.inner, "{: >5}: ", number)?, - None => self.inner.write_str(" ")?, - } - } else if i > 0 { + if i > 0 { self.inner.write_char('\n')?; - if self.number.is_some() { - self.inner.write_str(" ")?; - } else { - self.inner.write_str(" ")?; - } + self.inner.write_str(" ")?; } self.inner.write_str(line)?; diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index 82ef39ae90fb6..0835e282c46c3 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -82,8 +82,11 @@ fn multi_line_formatting() { let error = SuperError { source: SuperErrorSideKick }; let report = Report::new(&error).pretty(true); let actual = report.to_string(); - let expected = - String::from("SuperError is here!\n\nCaused by:\n SuperErrorSideKick is here!"); + let expected = String::from("\ +SuperError is here! + +Caused by: + SuperErrorSideKick is here!"); assert_eq!(expected, actual); } @@ -109,10 +112,11 @@ fn error_with_no_sources_formats_multi_line_correctly() { #[test] fn error_with_backtrace_outputs_correctly_with_one_source() { let trace = Backtrace::force_capture(); - let expected = format!("The source of the error + let expected = format!("\ +The source of the error Caused by: - Error with backtrace + Error with backtrace Stack backtrace: {}", trace); @@ -129,11 +133,12 @@ Stack backtrace: #[test] fn error_with_backtrace_outputs_correctly_with_two_sources() { let trace = Backtrace::force_capture(); - let expected = format!("Error with two sources + let expected = format!("\ +Error with two sources Caused by: - 0: The source of the error - 1: Error with backtrace + 0: The source of the error + 1: Error with backtrace Stack backtrace: {}", trace); @@ -211,7 +216,8 @@ fn error_formats_single_line_with_rude_display_impl() { let error = GenericError::new_with_source(MyMessage, error); let error = GenericError::new_with_source(MyMessage, error); let report = Report::new(error); - let expected = r#"line 1 + let expected = "\ +line 1 line 2 line 3 line 4 @@ -231,7 +237,7 @@ line 2 line 3 line 4 line 5 -line 6"#; +line 6"; let actual = report.to_string(); assert_eq!(expected, actual); @@ -256,7 +262,7 @@ fn error_formats_multi_line_with_rude_display_impl() { let error = GenericError::new_with_source(MyMessage, error); let error = GenericError::new_with_source(MyMessage, error); let report = Report::new(error).pretty(true); - let expected = r#"line 1 + let expected = "line 1 line 2 line 3 line 4 @@ -264,24 +270,24 @@ line 5 line 6 Caused by: - 0: line 1 - line 2 - line 3 - line 4 - line 5 - line 6 - 1: line 1 - line 2 - line 3 - line 4 - line 5 - line 6 - 2: line 1 - line 2 - line 3 - line 4 - line 5 - line 6"#; + 0: line 1 + line 2 + line 3 + line 4 + line 5 + line 6 + 1: line 1 + line 2 + line 3 + line 4 + line 5 + line 6 + 2: line 1 + line 2 + line 3 + line 4 + line 5 + line 6"; let actual = report.to_string(); assert_eq!(expected, actual); @@ -302,19 +308,48 @@ fn errors_that_start_with_newline_formats_correctly() { let error = GenericError::new_with_source(MyMessage, error); let error = GenericError::new_with_source(MyMessage, error); let report = Report::new(error).pretty(true); - let expected = r#" + let expected = " The message Caused by: - 0: - The message - - 1: - The message - "#; + 0: + The message + + 1: + The message + "; + + let actual = report.to_string(); + assert_eq!(expected, actual); +} + +#[test] +fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() { + #[derive(Debug)] + struct MyMessage; + + impl fmt::Display for MyMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("The message")?; + f.write_str(" goes on")?; + f.write_str(" and on.") + } + } + + let error = GenericError::new(MyMessage); + let error = GenericError::new_with_source(MyMessage, error); + let error = GenericError::new_with_source(MyMessage, error); + let report = Report::new(error).pretty(true); + let expected = "\ +The message goes on and on. + +Caused by: + 0: The message goes on and on. + 1: The message goes on and on."; let actual = report.to_string(); + println!("{}", actual); assert_eq!(expected, actual); } @@ -333,10 +368,11 @@ fn errors_with_string_interpolation_formats_correctly() { let error = GenericError::new(MyMessage(10)); let error = GenericError::new_with_source(MyMessage(20), error); let report = Report::new(error).pretty(true); - let expected = r#"Got an error code: (20). What would you like to do in response? + let expected = "\ +Got an error code: (20). What would you like to do in response? Caused by: - Got an error code: (10). What would you like to do in response?"#; + Got an error code: (10). What would you like to do in response?"; let actual = report.to_string(); assert_eq!(expected, actual); } @@ -356,17 +392,18 @@ fn empty_lines_mid_message() { let error = GenericError::new_with_source(MyMessage, error); let error = GenericError::new_with_source(MyMessage, error); let report = Report::new(error).pretty(true); - let expected = r#"line 1 + let expected = "\ +line 1 line 2 Caused by: - 0: line 1 - - line 2 - 1: line 1 - - line 2"#; + 0: line 1 + + line 2 + 1: line 1 + + line 2"; let actual = report.to_string(); assert_eq!(expected, actual); @@ -386,12 +423,13 @@ fn only_one_source() { let error = GenericError::new(MyMessage); let error = GenericError::new_with_source(MyMessage, error); let report = Report::new(error).pretty(true); - let expected = r#"line 1 + let expected = "\ +line 1 line 2 Caused by: - line 1 - line 2"#; + line 1 + line 2"; let actual = report.to_string(); assert_eq!(expected, actual); From 078b112d9452eb24cf6d5dffe8f4479cbe830d4e Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 14:22:35 -0800 Subject: [PATCH 13/31] add a panicking example --- library/std/src/error.rs | 55 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index a2b4eb2117dcc..cb74a0084c66d 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -857,14 +857,61 @@ impl dyn Error + Send + Sync { /// /// fn main() { /// match get_super_error() { -/// Err(e) => { -/// let report = Report::new(e).pretty(true); -/// println!("Error: {}", report); -/// } +/// Err(e) => println!("Error: {}", Report::new(e)), /// _ => println!("No error"), /// } /// } /// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here!: SuperErrorSideKick is here! +/// ``` +/// +/// Report prints the same output via `Display` and `Debug`, so it works well with +/// [`unwrap`]/[`expect`]: +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: SuperErrorSideKick, +/// # } +/// # impl fmt::Display for SuperError { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperError is here!") +/// # } +/// # } +/// # impl Error for SuperError { +/// # fn source(&self) -> Option<&(dyn Error + 'static)> { +/// # Some(&self.source) +/// # } +/// # } +/// # #[derive(Debug)] +/// # struct SuperErrorSideKick; +/// # impl fmt::Display for SuperErrorSideKick { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperErrorSideKick is here!") +/// # } +/// # } +/// # impl Error for SuperErrorSideKick {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// get_super_error().map_err(Report::new).unwrap(); +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 +/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +/// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { /// The error being reported. From 9be1cc9b6133fc8341ab605d426e675746144f29 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 15:32:31 -0800 Subject: [PATCH 14/31] more docs improvements --- library/std/src/error.rs | 242 +++++++++++++++++++++++++++++++++------ 1 file changed, 207 insertions(+), 35 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index cb74a0084c66d..07f04aa2b911b 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -869,8 +869,10 @@ impl dyn Error + Send + Sync { /// Error: SuperError is here!: SuperErrorSideKick is here! /// ``` /// +/// ## Output consistency +/// /// Report prints the same output via `Display` and `Debug`, so it works well with -/// [`unwrap`]/[`expect`]: +/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`: /// /// ```should_panic /// #![feature(error_reporter)] @@ -912,6 +914,104 @@ impl dyn Error + Send + Sync { /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace /// ``` +// /// TODO: Report doesn't yet support return from `main` gracefully, fix in followup (yaahc) +// /// ## Return from `main` +// /// +// /// `Report` also implements `From` for all types that implement [`Error`], this when combined with +// /// the `Debug` output means `Report` is an ideal starting place for formatting errors returned +// /// from `main`. +// /// +// /// ``` +// /// #![feature(error_reporter)] +// /// use std::error::Report; +// /// # use std::error::Error; +// /// # use std::fmt; +// /// # #[derive(Debug)] +// /// # struct SuperError { +// /// # source: SuperErrorSideKick, +// /// # } +// /// # impl fmt::Display for SuperError { +// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// /// # write!(f, "SuperError is here!") +// /// # } +// /// # } +// /// # impl Error for SuperError { +// /// # fn source(&self) -> Option<&(dyn Error + 'static)> { +// /// # Some(&self.source) +// /// # } +// /// # } +// /// # #[derive(Debug)] +// /// # struct SuperErrorSideKick; +// /// # impl fmt::Display for SuperErrorSideKick { +// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// /// # write!(f, "SuperErrorSideKick is here!") +// /// # } +// /// # } +// /// # impl Error for SuperErrorSideKick {} +// /// # fn get_super_error() -> Result<(), SuperError> { +// /// # Err(SuperError { source: SuperErrorSideKick }) +// /// # } +// /// +// /// fn main() -> Result<(), Report> { +// /// get_super_error()?; +// /// } +// /// ``` +// /// +// /// This example produces the following output: +// /// +// /// ```console +// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 +// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +// /// ``` +// /// +// /// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line +// /// output format, if you want to make sure your `Report`s are pretty printed and include backtrace +// /// you will need to manually convert and enable those flags. +// /// +// /// ``` +// /// #![feature(error_reporter)] +// /// use std::error::Report; +// /// # use std::error::Error; +// /// # use std::fmt; +// /// # #[derive(Debug)] +// /// # struct SuperError { +// /// # source: SuperErrorSideKick, +// /// # } +// /// # impl fmt::Display for SuperError { +// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// /// # write!(f, "SuperError is here!") +// /// # } +// /// # } +// /// # impl Error for SuperError { +// /// # fn source(&self) -> Option<&(dyn Error + 'static)> { +// /// # Some(&self.source) +// /// # } +// /// # } +// /// # #[derive(Debug)] +// /// # struct SuperErrorSideKick; +// /// # impl fmt::Display for SuperErrorSideKick { +// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// /// # write!(f, "SuperErrorSideKick is here!") +// /// # } +// /// # } +// /// # impl Error for SuperErrorSideKick {} +// /// # fn get_super_error() -> Result<(), SuperError> { +// /// # Err(SuperError { source: SuperErrorSideKick }) +// /// # } +// /// +// /// fn main() -> Result<(), Report> { +// /// get_super_error() +// /// .map_err(Report::new) +// /// .map_err(|r| r.pretty(true).show_backtrace(true))?; +// /// } +// /// ``` +// /// +// /// This example produces the following output: +// /// +// /// ```console +// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 +// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +// /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub struct Report { /// The error being reported. @@ -977,6 +1077,68 @@ where /// Caused by: /// SuperErrorSideKick is here! /// ``` + /// + /// When there are multiple source errors the causes will be numbered in order of iteration + /// starting from the outermost error. + /// + /// ```rust + /// #![feature(error_reporter)] + /// use std::error::Report; + /// # use std::error::Error; + /// # use std::fmt; + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: SuperErrorSideKick, + /// # } + /// # impl fmt::Display for SuperError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperError is here!") + /// # } + /// # } + /// # impl Error for SuperError { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKick { + /// # source: SuperErrorSideKickSideKick, + /// # } + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKick { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } + /// # #[derive(Debug)] + /// # struct SuperErrorSideKickSideKick; + /// # impl fmt::Display for SuperErrorSideKickSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKickSideKick is here!") + /// # } + /// # } + /// # impl Error for SuperErrorSideKickSideKick { } + /// + /// let source = SuperErrorSideKickSideKick; + /// let source = SuperErrorSideKick { source }; + /// let error = SuperError { source }; + /// let report = Report::new(error).pretty(true); + /// eprintln!("Error: {:?}", report); + /// ``` + /// + /// This example produces the following output: + /// + /// ```console + /// Error: SuperError is here! + /// + /// Caused by: + /// 0: SuperErrorSideKick is here! + /// 1: SuperErrorSideKickSideKick is here! + /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn pretty(mut self, pretty: bool) -> Self { self.pretty = pretty; @@ -987,38 +1149,40 @@ where /// /// # Examples /// + /// **Note**: Report will search for the first `Backtrace` it can find starting from the + /// outermost error. In this example it will display the backtrace from the second error in the + /// chain, `SuperErrorSideKick`. + /// /// ```rust /// #![feature(error_reporter)] /// #![feature(backtrace)] - /// use std::error::{Error, Report}; + /// # use std::error::Error; + /// # use std::fmt; + /// use std::error::Report; /// use std::backtrace::Backtrace; - /// use std::fmt; - /// - /// #[derive(Debug)] - /// struct SuperError { - /// source: SuperErrorSideKick, - /// } - /// - /// impl fmt::Display for SuperError { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "SuperError is here!") - /// } - /// } - /// - /// impl Error for SuperError { - /// fn source(&self) -> Option<&(dyn Error + 'static)> { - /// Some(&self.source) - /// } - /// } /// + /// # #[derive(Debug)] + /// # struct SuperError { + /// # source: SuperErrorSideKick, + /// # } + /// # impl fmt::Display for SuperError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperError is here!") + /// # } + /// # } + /// # impl Error for SuperError { + /// # fn source(&self) -> Option<&(dyn Error + 'static)> { + /// # Some(&self.source) + /// # } + /// # } /// #[derive(Debug)] /// struct SuperErrorSideKick { /// backtrace: Backtrace, /// } /// - /// impl fmt::Display for SuperErrorSideKick { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "SuperErrorSideKick is here!") + /// impl SuperErrorSideKick { + /// fn new() -> SuperErrorSideKick { + /// SuperErrorSideKick { backtrace: Backtrace::force_capture() } /// } /// } /// @@ -1028,7 +1192,14 @@ where /// } /// } /// - /// let source = SuperErrorSideKick { backtrace: Backtrace::force_capture() }; + /// // The rest of the example is unchanged ... + /// # impl fmt::Display for SuperErrorSideKick { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "SuperErrorSideKick is here!") + /// # } + /// # } + /// + /// let source = SuperErrorSideKick::new(); /// let error = SuperError { source }; /// let report = Report::new(error).pretty(true).show_backtrace(true); /// eprintln!("Error: {:?}", report); @@ -1043,17 +1214,18 @@ where /// SuperErrorSideKick is here! /// /// Stack backtrace: - /// 0: rust_out::main::_doctest_main_src_error_rs_943_0 - /// 1: rust_out::main - /// 2: core::ops::function::FnOnce::call_once - /// 3: std::sys_common::backtrace::__rust_begin_short_backtrace - /// 4: std::rt::lang_start::{{closure}} - /// 5: std::panicking::try - /// 6: std::rt::lang_start_internal - /// 7: std::rt::lang_start - /// 8: main - /// 9: __libc_start_main - /// 10: _start + /// 0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new + /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0 + /// 2: rust_out::main + /// 3: core::ops::function::FnOnce::call_once + /// 4: std::sys_common::backtrace::__rust_begin_short_backtrace + /// 5: std::rt::lang_start::{{closure}} + /// 6: std::panicking::try + /// 7: std::rt::lang_start_internal + /// 8: std::rt::lang_start + /// 9: main + /// 10: __libc_start_main + /// 11: _start /// ``` #[unstable(feature = "error_reporter", issue = "90172")] pub fn show_backtrace(mut self, show_backtrace: bool) -> Self { From 5b3902fc6550f7646c4612c7ff8f4d8712f13334 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Thu, 16 Dec 2021 16:08:30 -0800 Subject: [PATCH 15/31] attempt to make Report usable with Box dyn Error and fn main --- library/std/src/error.rs | 304 ++++++++++++++++++++++++++------------- 1 file changed, 201 insertions(+), 103 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 07f04aa2b911b..5514876c5d3b8 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -914,106 +914,109 @@ impl dyn Error + Send + Sync { /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace /// ``` -// /// TODO: Report doesn't yet support return from `main` gracefully, fix in followup (yaahc) -// /// ## Return from `main` -// /// -// /// `Report` also implements `From` for all types that implement [`Error`], this when combined with -// /// the `Debug` output means `Report` is an ideal starting place for formatting errors returned -// /// from `main`. -// /// -// /// ``` -// /// #![feature(error_reporter)] -// /// use std::error::Report; -// /// # use std::error::Error; -// /// # use std::fmt; -// /// # #[derive(Debug)] -// /// # struct SuperError { -// /// # source: SuperErrorSideKick, -// /// # } -// /// # impl fmt::Display for SuperError { -// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// /// # write!(f, "SuperError is here!") -// /// # } -// /// # } -// /// # impl Error for SuperError { -// /// # fn source(&self) -> Option<&(dyn Error + 'static)> { -// /// # Some(&self.source) -// /// # } -// /// # } -// /// # #[derive(Debug)] -// /// # struct SuperErrorSideKick; -// /// # impl fmt::Display for SuperErrorSideKick { -// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// /// # write!(f, "SuperErrorSideKick is here!") -// /// # } -// /// # } -// /// # impl Error for SuperErrorSideKick {} -// /// # fn get_super_error() -> Result<(), SuperError> { -// /// # Err(SuperError { source: SuperErrorSideKick }) -// /// # } -// /// -// /// fn main() -> Result<(), Report> { -// /// get_super_error()?; -// /// } -// /// ``` -// /// -// /// This example produces the following output: -// /// -// /// ```console -// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 -// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -// /// ``` -// /// -// /// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line -// /// output format, if you want to make sure your `Report`s are pretty printed and include backtrace -// /// you will need to manually convert and enable those flags. -// /// -// /// ``` -// /// #![feature(error_reporter)] -// /// use std::error::Report; -// /// # use std::error::Error; -// /// # use std::fmt; -// /// # #[derive(Debug)] -// /// # struct SuperError { -// /// # source: SuperErrorSideKick, -// /// # } -// /// # impl fmt::Display for SuperError { -// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// /// # write!(f, "SuperError is here!") -// /// # } -// /// # } -// /// # impl Error for SuperError { -// /// # fn source(&self) -> Option<&(dyn Error + 'static)> { -// /// # Some(&self.source) -// /// # } -// /// # } -// /// # #[derive(Debug)] -// /// # struct SuperErrorSideKick; -// /// # impl fmt::Display for SuperErrorSideKick { -// /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// /// # write!(f, "SuperErrorSideKick is here!") -// /// # } -// /// # } -// /// # impl Error for SuperErrorSideKick {} -// /// # fn get_super_error() -> Result<(), SuperError> { -// /// # Err(SuperError { source: SuperErrorSideKick }) -// /// # } -// /// -// /// fn main() -> Result<(), Report> { -// /// get_super_error() -// /// .map_err(Report::new) -// /// .map_err(|r| r.pretty(true).show_backtrace(true))?; -// /// } -// /// ``` -// /// -// /// This example produces the following output: -// /// -// /// ```console -// /// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40 -// /// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -// /// ``` +/// +/// ## Return from `main` +/// +/// `Report` also implements `From` for all types that implement [`Error`], this when combined with +/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned +/// from `main`. +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: SuperErrorSideKick, +/// # } +/// # impl fmt::Display for SuperError { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperError is here!") +/// # } +/// # } +/// # impl Error for SuperError { +/// # fn source(&self) -> Option<&(dyn Error + 'static)> { +/// # Some(&self.source) +/// # } +/// # } +/// # #[derive(Debug)] +/// # struct SuperErrorSideKick; +/// # impl fmt::Display for SuperErrorSideKick { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperErrorSideKick is here!") +/// # } +/// # } +/// # impl Error for SuperErrorSideKick {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// fn main() -> Result<(), Report> { +/// get_super_error()?; +/// Ok(()) +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here!: SuperErrorSideKick is here! +/// ``` +/// +/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line +/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace +/// you will need to manually convert and enable those flags. +/// +/// ```should_panic +/// #![feature(error_reporter)] +/// use std::error::Report; +/// # use std::error::Error; +/// # use std::fmt; +/// # #[derive(Debug)] +/// # struct SuperError { +/// # source: SuperErrorSideKick, +/// # } +/// # impl fmt::Display for SuperError { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperError is here!") +/// # } +/// # } +/// # impl Error for SuperError { +/// # fn source(&self) -> Option<&(dyn Error + 'static)> { +/// # Some(&self.source) +/// # } +/// # } +/// # #[derive(Debug)] +/// # struct SuperErrorSideKick; +/// # impl fmt::Display for SuperErrorSideKick { +/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +/// # write!(f, "SuperErrorSideKick is here!") +/// # } +/// # } +/// # impl Error for SuperErrorSideKick {} +/// # fn get_super_error() -> Result<(), SuperError> { +/// # Err(SuperError { source: SuperErrorSideKick }) +/// # } +/// +/// fn main() -> Result<(), Report> { +/// get_super_error() +/// .map_err(Report::from) +/// .map_err(|r| r.pretty(true).show_backtrace(true))?; +/// Ok(()) +/// } +/// ``` +/// +/// This example produces the following output: +/// +/// ```console +/// Error: SuperError is here! +/// +/// Caused by: +/// SuperErrorSideKick is here! +/// ``` #[unstable(feature = "error_reporter", issue = "90172")] -pub struct Report { +pub struct Report> { /// The error being reported. error: E, /// Whether a backtrace should be included as part of the report. @@ -1024,14 +1027,16 @@ pub struct Report { impl Report where - E: Error, + Report: From, { /// Create a new `Report` from an input error. #[unstable(feature = "error_reporter", issue = "90172")] pub fn new(error: E) -> Report { - Report { error, show_backtrace: false, pretty: false } + Self::from(error) } +} +impl Report { /// Enable pretty-printing the report across multiple lines. /// /// # Examples @@ -1232,7 +1237,81 @@ where self.show_backtrace = show_backtrace; self } +} + +impl Report +where + E: Error, +{ + fn backtrace(&self) -> Option<&Backtrace> { + // have to grab the backtrace on the first error directly since that error may not be + // 'static + let backtrace = self.error.backtrace(); + let backtrace = backtrace.or_else(|| { + self.error + .source() + .map(|source| source.chain().find_map(|source| source.backtrace())) + .flatten() + }); + backtrace + } + + /// Format the report as a single line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.error)?; + + let sources = self.error.source().into_iter().flat_map(::chain); + + for cause in sources { + write!(f, ": {}", cause)?; + } + + Ok(()) + } + + /// Format the report as multiple lines, with each error cause on its own line. + #[unstable(feature = "error_reporter", issue = "90172")] + fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let error = &self.error; + + write!(f, "{}", error)?; + + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; + + let multiple = cause.source().is_some(); + + for (ind, error) in cause.chain().enumerate() { + writeln!(f)?; + let mut indented = Indented { + inner: f, + }; + if multiple { + write!(indented, "{: >4}: {}", ind, error)?; + } else { + write!(indented, " {}", error)?; + } + } + } + + if self.show_backtrace { + let backtrace = self.backtrace(); + + if let Some(backtrace) = backtrace { + let backtrace = backtrace.to_string(); + + f.write_str("\n\nStack backtrace:\n")?; + f.write_str(backtrace.trim_end())?; + } + } + + Ok(()) + } +} +impl Report> +{ fn backtrace(&self) -> Option<&Backtrace> { // have to grab the backtrace on the first error directly since that error may not be // 'static @@ -1306,7 +1385,18 @@ where E: Error, { fn from(error: E) -> Self { - Report::new(error) + Report { error, show_backtrace: false, pretty: false } + } +} + +#[unstable(feature = "error_reporter", issue = "90172")] +impl<'a, E> From for Report> +where + E: Error + 'a, +{ + fn from(error: E) -> Self { + let error = box error; + Report { error, show_backtrace: false, pretty: false } } } @@ -1320,12 +1410,20 @@ where } } +#[unstable(feature = "error_reporter", issue = "90172")] +impl fmt::Display for Report> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } + } +} + // This type intentionally outputs the same format for `Display` and `Debug`for // situations where you unwrap a `Report` or return it from main. #[unstable(feature = "error_reporter", issue = "90172")] impl fmt::Debug for Report where - E: Error, + Report: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) From 341d65d975453af9e548f1f668256604dc1f156a Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 20 Dec 2021 16:36:38 -0500 Subject: [PATCH 16/31] Add test case for #86177 and #85718 --- .../coverage-reports/expected_show_coverage.unused_mod.txt | 7 +++++++ .../run-make-fulldeps/coverage/lib/unused_mod_helper.rs | 3 +++ src/test/run-make-fulldeps/coverage/unused_mod.rs | 6 ++++++ 3 files changed, 16 insertions(+) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt create mode 100644 src/test/run-make-fulldeps/coverage/lib/unused_mod_helper.rs create mode 100644 src/test/run-make-fulldeps/coverage/unused_mod.rs diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt new file mode 100644 index 0000000000000..0ee80350e1134 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt @@ -0,0 +1,7 @@ + 1| |#[path = "lib/unused_mod_helper.rs"] + 2| |mod unused_module; + 3| | + 4| 1|fn main() { + 5| 1| println!("hello world!"); + 6| 1|} + diff --git a/src/test/run-make-fulldeps/coverage/lib/unused_mod_helper.rs b/src/test/run-make-fulldeps/coverage/lib/unused_mod_helper.rs new file mode 100644 index 0000000000000..ae1cc1531ed75 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/lib/unused_mod_helper.rs @@ -0,0 +1,3 @@ +pub fn never_called_function() { + println!("I am never called"); +} diff --git a/src/test/run-make-fulldeps/coverage/unused_mod.rs b/src/test/run-make-fulldeps/coverage/unused_mod.rs new file mode 100644 index 0000000000000..679b4e5318803 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/unused_mod.rs @@ -0,0 +1,6 @@ +#[path = "lib/unused_mod_helper.rs"] +mod unused_module; + +fn main() { + println!("hello world!"); +} From ef57f249a2244634a5c98d431d3bbfd715bd9c89 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 20 Dec 2021 16:36:56 -0500 Subject: [PATCH 17/31] [code coverage] Fix missing dead code in modules that are never called The issue here is that the logic used to determine which CGU to put the dead function stubs in doesn't handle cases where a module is never assigned to a CGU. The partitioning logic also caused issues in #85461 where inline functions were duplicated into multiple CGUs resulting in duplicate symbols. This commit fixes the issue by removing the complex logic used to assign dead code stubs to CGUs and replaces it with a much simplier model: we pick one CGU to hold all the dead code stubs. We pick a CGU which has exported items which increases the likelihood the linker won't throw away our dead functions and we pick the smallest to minimize the impact on compilation times for crates with very large CGUs. Fixes #86177 Fixes #85718 Fixes #79622 --- .../src/coverageinfo/mapgen.rs | 107 ++++-------------- compiler/rustc_middle/src/mir/mono.rs | 22 +++- compiler/rustc_middle/src/query/mod.rs | 10 -- .../rustc_mir_transform/src/coverage/query.rs | 20 ---- .../src/partitioning/mod.rs | 18 +++ .../expected_show_coverage.unused_mod.txt | 6 + .../expected_show_coverage.uses_crate.txt | 8 +- ...pected_show_coverage.uses_inline_crate.txt | 8 +- 8 files changed, 77 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index e0af5653753b6..ab3a0ef7f15db 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -5,12 +5,13 @@ use crate::llvm; use llvm::coverageinfo::CounterMappingRegion; use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression}; use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_data_structures::fx::FxIndexSet; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefIdSet; use rustc_llvm::RustString; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::CodeRegion; use rustc_middle::ty::TyCtxt; -use rustc_span::Symbol; use std::ffi::CString; @@ -46,7 +47,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { // functions exist. Generate synthetic functions with a (required) single counter, and add the // MIR `Coverage` code regions to the `function_coverage_map`, before calling // `ctx.take_function_coverage_map()`. - if !tcx.sess.instrument_coverage_except_unused_functions() { + if cx.codegen_unit.is_code_coverage_dead_code_cgu() { add_unused_functions(cx); } @@ -271,17 +272,12 @@ fn save_function_record( /// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query /// `codegened_and_inlined_items`). /// -/// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and -/// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`) -/// allocated to only one of those CGUs. We must NOT inject any unused functions's `CodeRegion`s -/// more than once, so we have to pick a CGUs `function_coverage_map` into which the unused -/// function will be inserted. +/// These unused functions are then codegen'd in one of the CGUs which is marked as the +/// "code coverage dead code cgu" during the partitioning process. fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { - let tcx = cx.tcx; + assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); - // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources - // of compiler state data that might help (or better sources that could be exposed, but - // aren't yet)? + let tcx = cx.tcx; let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics(); @@ -299,79 +295,24 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let codegenned_def_ids = tcx.codegened_and_inlined_items(()); - let mut unused_def_ids_by_file: FxHashMap> = FxHashMap::default(); for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) { - // Make sure the non-codegenned (unused) function has at least one MIR - // `Coverage` statement with a code region, and return its file name. - if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) { - let def_ids = - unused_def_ids_by_file.entry(*non_codegenned_file_name).or_insert_with(Vec::new); - def_ids.push(non_codegenned_def_id); - } - } - - if unused_def_ids_by_file.is_empty() { - // There are no unused functions with file names to add (in any CGU) - return; - } - - // Each `CodegenUnit` (CGU) has its own function_coverage_map, and generates a specific binary - // with its own coverage map. - // - // Each covered function `Instance` can be included in only one coverage map, produced from a - // specific function_coverage_map, from a specific CGU. - // - // Since unused functions did not generate code, they are not associated with any CGU yet. - // - // To avoid injecting the unused functions in multiple coverage maps (for multiple CGUs) - // determine which function_coverage_map has the responsibility for publishing unreachable - // coverage, based on file name: For each unused function, find the CGU that generates the - // first function (based on sorted `DefId`) from the same file. - // - // Add a new `FunctionCoverage` to the `function_coverage_map`, with unreachable code regions - // for each region in it's MIR. - - // Convert the `HashSet` of `codegenned_def_ids` to a sortable vector, and sort them. - let mut sorted_codegenned_def_ids: Vec = codegenned_def_ids.iter().copied().collect(); - sorted_codegenned_def_ids.sort_unstable(); - - let mut first_covered_def_id_by_file: FxHashMap = FxHashMap::default(); - for &def_id in sorted_codegenned_def_ids.iter() { - if let Some(covered_file_name) = tcx.covered_file_name(def_id) { - // Only add files known to have unused functions - if unused_def_ids_by_file.contains_key(covered_file_name) { - first_covered_def_id_by_file.entry(*covered_file_name).or_insert(def_id); + // `all_def_ids` contains things besides just "functions" such as constants, + // statics, etc. We need to filter those out. + let kind = tcx.def_kind(non_codegenned_def_id); + if matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator) { + let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id); + + // If a function is marked `#[no_coverage]`, then skip generating a + // dead code stub for it. + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + debug!("skipping unused fn marked #[no_coverage]: {:?}", non_codegenned_def_id); + continue; } - } - } - - // Get the set of def_ids with coverage regions, known by *this* CoverageContext. - let cgu_covered_def_ids: DefIdSet = match cx.coverage_context() { - Some(ctx) => ctx - .function_coverage_map - .borrow() - .keys() - .map(|&instance| instance.def.def_id()) - .collect(), - None => return, - }; - - let cgu_covered_files: FxHashSet = first_covered_def_id_by_file - .iter() - .filter_map( - |(&file_name, def_id)| { - if cgu_covered_def_ids.contains(def_id) { Some(file_name) } else { None } - }, - ) - .collect(); - // For each file for which this CGU is responsible for adding unused function coverage, - // get the `def_id`s for each unused function (if any), define a synthetic function with a - // single LLVM coverage counter, and add the function's coverage `CodeRegion`s. to the - // function_coverage_map. - for covered_file_name in cgu_covered_files { - for def_id in unused_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() { - cx.define_unused_fn(def_id); + debug!("generating unused fn: {:?}", non_codegenned_def_id); + cx.define_unused_fn(non_codegenned_def_id); + } else { + debug!("skipping unused {:?}: {:?}", kind, non_codegenned_def_id); } } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index fd8606e6929e2..a9d65a3192874 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -247,6 +247,9 @@ pub struct CodegenUnit<'tcx> { items: FxHashMap, (Linkage, Visibility)>, size_estimate: Option, primary: bool, + /// True if this is CGU is used to hold code coverage information for dead code, + /// false otherwise. + is_code_coverage_dead_code_cgu: bool, } /// Specifies the linkage type for a `MonoItem`. @@ -277,7 +280,13 @@ pub enum Visibility { impl<'tcx> CodegenUnit<'tcx> { #[inline] pub fn new(name: Symbol) -> CodegenUnit<'tcx> { - CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false } + CodegenUnit { + name, + items: Default::default(), + size_estimate: None, + primary: false, + is_code_coverage_dead_code_cgu: false, + } } pub fn name(&self) -> Symbol { @@ -304,6 +313,15 @@ impl<'tcx> CodegenUnit<'tcx> { &mut self.items } + pub fn is_code_coverage_dead_code_cgu(&self) -> bool { + self.is_code_coverage_dead_code_cgu + } + + /// Marks this CGU as the one used to contain code coverage information for dead code. + pub fn make_code_coverage_dead_code_cgu(&mut self) { + self.is_code_coverage_dead_code_cgu = true; + } + pub fn mangle_name(human_readable_name: &str) -> String { // We generate a 80 bit hash from the name. This should be enough to // avoid collisions and is still reasonably short for filenames. @@ -407,9 +425,11 @@ impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { // The size estimate is not relevant to the hash size_estimate: _, primary: _, + is_code_coverage_dead_code_cgu, } = *self; name.hash_stable(hcx, hasher); + is_code_coverage_dead_code_cgu.hash_stable(hcx, hasher); let mut items: Vec<(Fingerprint, _)> = items .iter() diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ad3f61d07843a..5990e34f34060 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -386,16 +386,6 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) } - /// Returns the name of the file that contains the function body, if instrumented for coverage. - query covered_file_name(key: DefId) -> Option { - desc { - |tcx| "retrieving the covered file name, if instrumented, for `{}`", - tcx.def_path_str(key) - } - storage(ArenaCacheSelector<'tcx>) - cache_on_disk_if { key.is_local() } - } - /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the /// function was optimized out before codegen, and before being added to the Coverage Map. query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> { diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 1721fb5cde0e8..46de6d939a1df 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -9,7 +9,6 @@ use rustc_span::def_id::DefId; /// A `query` provider for retrieving coverage information injected into MIR. pub(crate) fn provide(providers: &mut Providers) { providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id); - providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id); providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); } @@ -137,25 +136,6 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> coverage_visitor.info } -fn covered_file_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - if tcx.is_mir_available(def_id) { - let body = mir_body(tcx, def_id); - for bb_data in body.basic_blocks().iter() { - for statement in bb_data.statements.iter() { - if let StatementKind::Coverage(box ref coverage) = statement.kind { - if let Some(code_region) = coverage.code_region.as_ref() { - if is_inlined(body, statement) { - continue; - } - return Some(code_region.file_name); - } - } - } - } - } - return None; -} - fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> { let body = mir_body(tcx, def_id); body.basic_blocks() diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index dc22ffc6747ac..463c213536448 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -201,6 +201,24 @@ pub fn partition<'tcx>( partitioner.internalize_symbols(cx, &mut post_inlining); } + let instrument_dead_code = + tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions(); + + if instrument_dead_code { + // Find the smallest CGU that has exported symbols and put the dead + // function stubs in that CGU. We look for exported symbols to increase + // the likelyhood the linker won't throw away the dead functions. + let mut cgus_with_exported_symbols: Vec<_> = post_inlining + .codegen_units + .iter_mut() + .filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)) + .collect(); + cgus_with_exported_symbols.sort_by_key(|cgu| cgu.size_estimate()); + + let dead_code_cgu = cgus_with_exported_symbols.last_mut().unwrap(); + dead_code_cgu.make_code_coverage_dead_code_cgu(); + } + // Finally, sort by codegen unit name, so that we get deterministic results. let PostInliningPartitioning { codegen_units: mut result, diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt index 0ee80350e1134..d902b7a412f3b 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt @@ -1,3 +1,9 @@ +../coverage/lib/unused_mod_helper.rs: + 1| 0|pub fn never_called_function() { + 2| 0| println!("I am never called"); + 3| 0|} + +../coverage/unused_mod.rs: 1| |#[path = "lib/unused_mod_helper.rs"] 2| |mod unused_module; 3| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 768dcb2f6084c..c2d5143a61816 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} @@ -36,12 +36,12 @@ 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::>: + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_crate::used_only_from_this_lib_crate_generic_function::>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt index 89636294035df..dab31cbf4ac9e 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt @@ -42,12 +42,12 @@ 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 41| 2|} ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 41| 1|} ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 41| 1|} @@ -61,12 +61,12 @@ 46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 47| 4|} ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 47| 2|} ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: + | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 47| 2|} From ebc0d0d2a849ebf4cdca5f8cd4ce52d67a725bf6 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 20 Dec 2021 20:15:29 -0500 Subject: [PATCH 18/31] Address review comments --- .../src/coverageinfo/mapgen.rs | 47 +++++++++++-------- .../src/partitioning/mod.rs | 32 +++++++++---- .../expected_show_coverage.uses_crate.txt | 8 ++-- ...pected_show_coverage.uses_inline_crate.txt | 8 ++-- 4 files changed, 59 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index ab3a0ef7f15db..32f18419753e9 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -273,7 +273,9 @@ fn save_function_record( /// `codegened_and_inlined_items`). /// /// These unused functions are then codegen'd in one of the CGUs which is marked as the -/// "code coverage dead code cgu" during the partitioning process. +/// "code coverage dead code cgu" during the partitioning process. This prevents us from generating +/// code regions for the same function more than once which can lead to linker errors regarding +/// duplicate symbols. fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); @@ -281,12 +283,24 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics(); - let all_def_ids: DefIdSet = tcx + let eligible_def_ids: DefIdSet = tcx .mir_keys(()) .iter() .filter_map(|local_def_id| { let def_id = local_def_id.to_def_id(); - if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) { + let kind = tcx.def_kind(def_id); + // `mir_keys` will give us `DefId`s for all kinds of things, not + // just "functions", like consts, statics, etc. Filter those out. + // If `ignore_unused_generics` was specified, filter out any + // generic functions from consideration as well. + if !matches!( + kind, + DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator + ) { + return None; + } else if ignore_unused_generics + && tcx.generics_of(def_id).requires_monomorphization(tcx) + { return None; } Some(local_def_id.to_def_id()) @@ -295,24 +309,17 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { let codegenned_def_ids = tcx.codegened_and_inlined_items(()); - for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) { - // `all_def_ids` contains things besides just "functions" such as constants, - // statics, etc. We need to filter those out. - let kind = tcx.def_kind(non_codegenned_def_id); - if matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator) { - let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id); - - // If a function is marked `#[no_coverage]`, then skip generating a - // dead code stub for it. - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { - debug!("skipping unused fn marked #[no_coverage]: {:?}", non_codegenned_def_id); - continue; - } + for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) { + let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id); - debug!("generating unused fn: {:?}", non_codegenned_def_id); - cx.define_unused_fn(non_codegenned_def_id); - } else { - debug!("skipping unused {:?}: {:?}", kind, non_codegenned_def_id); + // If a function is marked `#[no_coverage]`, then skip generating a + // dead code stub for it. + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + debug!("skipping unused fn marked #[no_coverage]: {:?}", non_codegenned_def_id); + continue; } + + debug!("generating unused fn: {:?}", non_codegenned_def_id); + cx.define_unused_fn(non_codegenned_def_id); } } diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 463c213536448..67597a0d7b46b 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -205,17 +205,33 @@ pub fn partition<'tcx>( tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions(); if instrument_dead_code { + assert!( + post_inlining.codegen_units.len() > 0, + "There must be at least one CGU that code coverage data can be generated in." + ); + // Find the smallest CGU that has exported symbols and put the dead // function stubs in that CGU. We look for exported symbols to increase - // the likelyhood the linker won't throw away the dead functions. - let mut cgus_with_exported_symbols: Vec<_> = post_inlining - .codegen_units - .iter_mut() + // the likelihood the linker won't throw away the dead functions. + // FIXME(#92165): In order to truly resolve this, we need to make sure + // the object file (CGU) containing the dead function stubs is included + // in the final binary. This will probably require forcing these + // function symbols to be included via `-u` or `/include` linker args. + let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect(); + cgus.sort_by_key(|cgu| cgu.size_estimate()); + + let dead_code_cgu = if let Some(cgu) = cgus + .into_iter() + .rev() .filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)) - .collect(); - cgus_with_exported_symbols.sort_by_key(|cgu| cgu.size_estimate()); - - let dead_code_cgu = cgus_with_exported_symbols.last_mut().unwrap(); + .next() + { + cgu + } else { + // If there are no CGUs that have externally linked items, + // then we just pick the first CGU as a fallback. + &mut post_inlining.codegen_units[0] + }; dead_code_cgu.make_code_coverage_dead_code_cgu(); } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index c2d5143a61816..768dcb2f6084c 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} @@ -36,12 +36,12 @@ 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_crate::used_only_from_this_lib_crate_generic_function::>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::>: + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt index dab31cbf4ac9e..89636294035df 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt @@ -42,12 +42,12 @@ 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 41| 2|} ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 41| 1|} ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 41| 1|} @@ -61,12 +61,12 @@ 46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 47| 4|} ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: + | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 47| 2|} ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 47| 2|} From 336c85a053ff502fb2f42d2579fcff61efd6bdda Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 27 Dec 2021 13:44:14 -0800 Subject: [PATCH 19/31] rustdoc: Preserve rendering of macro_rules matchers when possible --- src/librustdoc/clean/utils.rs | 61 +++++++++++++++++++++++++++--- src/test/rustdoc/decl_macro.rs | 12 +++--- src/test/rustdoc/macros.rs | 8 ++-- src/test/rustdoc/reexports-priv.rs | 8 ++-- src/test/rustdoc/reexports.rs | 4 +- 5 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 7d5e2e36bd190..5fe7dd6c2bc83 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -16,6 +16,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; @@ -484,20 +486,67 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL"); /// Render a sequence of macro arms in a format suitable for displaying to the user /// as part of an item declaration. pub(super) fn render_macro_arms<'a>( + cx: &DocContext<'_>, matchers: impl Iterator, arm_delim: &str, ) -> String { let mut out = String::new(); for matcher in matchers { - writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(matcher), arm_delim).unwrap(); + writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(cx, matcher), arm_delim) + .unwrap(); } out } /// Render a macro matcher in a format suitable for displaying to the user /// as part of an item declaration. -pub(super) fn render_macro_matcher(matcher: &TokenTree) -> String { - rustc_ast_pretty::pprust::tt_to_string(matcher) +pub(super) fn render_macro_matcher(cx: &DocContext<'_>, matcher: &TokenTree) -> String { + if let Some(snippet) = snippet_equal_to_token(cx, matcher) { + snippet + } else { + rustc_ast_pretty::pprust::tt_to_string(matcher) + } +} + +/// Find the source snippet for this token's Span, reparse it, and return the +/// snippet if the reparsed TokenTree matches the argument TokenTree. +fn snippet_equal_to_token(cx: &DocContext<'_>, matcher: &TokenTree) -> Option { + // Find what rustc thinks is the source snippet. + // This may not actually be anything meaningful if this matcher was itself + // generated by a macro. + let source_map = cx.sess().source_map(); + let span = matcher.span(); + let snippet = source_map.span_to_snippet(span).ok()?; + + // Create a Parser. + let sess = ParseSess::new(FilePathMapping::empty()); + let file_name = source_map.span_to_filename(span); + let mut parser = + match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) { + Ok(parser) => parser, + Err(diagnostics) => { + for mut diagnostic in diagnostics { + diagnostic.cancel(); + } + return None; + } + }; + + // Reparse a single token tree. + let mut reparsed_trees = match parser.parse_all_token_trees() { + Ok(reparsed_trees) => reparsed_trees, + Err(mut diagnostic) => { + diagnostic.cancel(); + return None; + } + }; + if reparsed_trees.len() != 1 { + return None; + } + let reparsed_tree = reparsed_trees.pop().unwrap(); + + // Compare against the original tree. + if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None } } pub(super) fn display_macro_source( @@ -512,21 +561,21 @@ pub(super) fn display_macro_source( let matchers = tts.chunks(4).map(|arm| &arm[0]); if def.macro_rules { - format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(matchers, ";")) + format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx, matchers, ";")) } else { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", vis.to_src_with_space(cx.tcx, def_id), name, - matchers.map(render_macro_matcher).collect::(), + matchers.map(|matcher| render_macro_matcher(cx, matcher)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", vis.to_src_with_space(cx.tcx, def_id), name, - render_macro_arms(matchers, ","), + render_macro_arms(cx, matchers, ","), ) } } diff --git a/src/test/rustdoc/decl_macro.rs b/src/test/rustdoc/decl_macro.rs index fe19dadbe0243..94ade31b5e5f4 100644 --- a/src/test/rustdoc/decl_macro.rs +++ b/src/test/rustdoc/decl_macro.rs @@ -9,7 +9,7 @@ pub macro my_macro() { } -// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok : tt) *) {' +// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok:tt)*) {' // @has - //pre '...' // @has - //pre '}' pub macro my_macro_2($($tok:tt)*) { @@ -18,8 +18,8 @@ pub macro my_macro_2($($tok:tt)*) { // @has decl_macro/macro.my_macro_multi.html //pre 'pub macro my_macro_multi {' // @has - //pre '(_) => { ... },' -// @has - //pre '($foo : ident.$bar : expr) => { ... },' -// @has - //pre '($($foo : literal), +) => { ... },' +// @has - //pre '($foo:ident . $bar:expr) => { ... },' +// @has - //pre '($($foo:literal),+) => { ... },' // @has - //pre '}' pub macro my_macro_multi { (_) => { @@ -33,7 +33,7 @@ pub macro my_macro_multi { } } -// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo : expr) {' +// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo:expr) {' // @has - //pre '...' // @has - //pre '}' pub macro by_example_single { @@ -42,12 +42,12 @@ pub macro by_example_single { mod a { mod b { - // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo : expr) {' + // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {' pub(in super) macro by_example_vis { ($foo:expr) => {} } mod c { - // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo : expr) {' + // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {' pub(in a) macro by_example_vis_named { ($foo:expr) => {} } diff --git a/src/test/rustdoc/macros.rs b/src/test/rustdoc/macros.rs index 1cd454720e7d1..ae0cf7a14789d 100644 --- a/src/test/rustdoc/macros.rs +++ b/src/test/rustdoc/macros.rs @@ -1,7 +1,7 @@ // @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {' // @has - //pre '() => { ... };' -// @has - //pre '($a : tt) => { ... };' -// @has - //pre '($e : expr) => { ... };' +// @has - //pre '($a:tt) => { ... };' +// @has - //pre '($e:expr) => { ... };' #[macro_export] macro_rules! my_macro { () => []; @@ -12,8 +12,8 @@ macro_rules! my_macro { // Check that exported macro defined in a module are shown at crate root. // @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {' // @has - //pre '() => { ... };' -// @has - //pre '($a : tt) => { ... };' -// @has - //pre '($e : expr) => { ... };' +// @has - //pre '($a:tt) => { ... };' +// @has - //pre '($e:expr) => { ... };' mod sub { #[macro_export] macro_rules! my_sub_macro { diff --git a/src/test/rustdoc/reexports-priv.rs b/src/test/rustdoc/reexports-priv.rs index 95f741807494c..aea9b9f2b395d 100644 --- a/src/test/rustdoc/reexports-priv.rs +++ b/src/test/rustdoc/reexports-priv.rs @@ -5,7 +5,7 @@ extern crate reexports; -// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' +// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; // @!has 'foo/macro.addr_of_crate.html' pub(crate) use reexports::addr_of_crate; @@ -61,11 +61,11 @@ use reexports::UnionLocal; pub mod outer { pub mod inner { - // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; - // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {' pub(crate) use reexports::addr_of_crate; - // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {' pub(super) use reexports::addr_of_super; // @!has 'foo/outer/inner/macro.addr_of_self.html' pub(self) use reexports::addr_of_self; diff --git a/src/test/rustdoc/reexports.rs b/src/test/rustdoc/reexports.rs index 3b31530847035..7abcbfb618122 100644 --- a/src/test/rustdoc/reexports.rs +++ b/src/test/rustdoc/reexports.rs @@ -4,7 +4,7 @@ extern crate reexports; -// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' +// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; // @!has 'foo/macro.addr_of_crate.html' pub(crate) use reexports::addr_of_crate; @@ -60,7 +60,7 @@ use reexports::UnionLocal; pub mod outer { pub mod inner { - // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {' + // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {' pub use reexports::addr_of; // @!has 'foo/outer/inner/macro.addr_of_crate.html' pub(crate) use reexports::addr_of_crate; From 544a6bb7e72c907f05881ae7f461005cc5f92759 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 28 Dec 2021 13:43:08 -0800 Subject: [PATCH 20/31] Replace &DocCtxt -> TyCtxt in macro matcher rendering --- src/librustdoc/clean/utils.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 5fe7dd6c2bc83..2c3fd39baf69f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -486,13 +486,13 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL"); /// Render a sequence of macro arms in a format suitable for displaying to the user /// as part of an item declaration. pub(super) fn render_macro_arms<'a>( - cx: &DocContext<'_>, + tcx: TyCtxt<'_>, matchers: impl Iterator, arm_delim: &str, ) -> String { let mut out = String::new(); for matcher in matchers { - writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(cx, matcher), arm_delim) + writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim) .unwrap(); } out @@ -500,8 +500,8 @@ pub(super) fn render_macro_arms<'a>( /// Render a macro matcher in a format suitable for displaying to the user /// as part of an item declaration. -pub(super) fn render_macro_matcher(cx: &DocContext<'_>, matcher: &TokenTree) -> String { - if let Some(snippet) = snippet_equal_to_token(cx, matcher) { +pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String { + if let Some(snippet) = snippet_equal_to_token(tcx, matcher) { snippet } else { rustc_ast_pretty::pprust::tt_to_string(matcher) @@ -510,11 +510,11 @@ pub(super) fn render_macro_matcher(cx: &DocContext<'_>, matcher: &TokenTree) -> /// Find the source snippet for this token's Span, reparse it, and return the /// snippet if the reparsed TokenTree matches the argument TokenTree. -fn snippet_equal_to_token(cx: &DocContext<'_>, matcher: &TokenTree) -> Option { +fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option { // Find what rustc thinks is the source snippet. // This may not actually be anything meaningful if this matcher was itself // generated by a macro. - let source_map = cx.sess().source_map(); + let source_map = tcx.sess.source_map(); let span = matcher.span(); let snippet = source_map.span_to_snippet(span).ok()?; @@ -561,21 +561,21 @@ pub(super) fn display_macro_source( let matchers = tts.chunks(4).map(|arm| &arm[0]); if def.macro_rules { - format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx, matchers, ";")) + format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";")) } else { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", vis.to_src_with_space(cx.tcx, def_id), name, - matchers.map(|matcher| render_macro_matcher(cx, matcher)).collect::(), + matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", vis.to_src_with_space(cx.tcx, def_id), name, - render_macro_arms(cx, matchers, ","), + render_macro_arms(cx.tcx, matchers, ","), ) } } From 0f8415b8e1d93de7b6673298c9f10c709742d9ab Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 28 Dec 2021 13:52:33 -0800 Subject: [PATCH 21/31] Add a test of rustdoc on macro-generated macro --- src/test/rustdoc/macro-generated-macro.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/rustdoc/macro-generated-macro.rs diff --git a/src/test/rustdoc/macro-generated-macro.rs b/src/test/rustdoc/macro-generated-macro.rs new file mode 100644 index 0000000000000..25d8bc3ec6281 --- /dev/null +++ b/src/test/rustdoc/macro-generated-macro.rs @@ -0,0 +1,14 @@ +macro_rules! outer { + ($($matcher:tt)*) => { + #[macro_export] + macro_rules! inner { + (<= $($matcher)* =>) => {}; + } + } +} + +// @has macro_generated_macro/macro.inner.html //pre 'macro_rules! inner {' +// @has - //pre '(<= type $($i : ident) :: * + $e : expr =>) => { ... };' +outer!(type $($i:ident)::* + $e:expr); + +inner!(<= type foo::bar + x.sort() =>); From 579e8bce7df948c786ab89f2a5d4b949cf44a44d Mon Sep 17 00:00:00 2001 From: Lain Yang Date: Fri, 7 Jan 2022 10:47:27 +0800 Subject: [PATCH 22/31] Make rlib metadata strip works with MIPSr6 architecture Because MIPSr6 has many differences with previous MIPSr2 arch, the previous rlib metadata stripping code in `rustc_codegen_ssa` is only for MIPSr2/r3/r5 (which share the same elf e_flags). This commit fixed this problem. It makes `rustc_codegen_ssa` happy when compiling rustc for MIPSr6 target or hosts. --- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/src/back/metadata.rs | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 5c13dfdc1b505..b810e615661e0 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -41,6 +41,6 @@ rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } [dependencies.object] -version = "0.26.2" +version = "0.27.0" default-features = false features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"] diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 79c24f0f17280..9862c3fb16eab 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -135,12 +135,24 @@ fn create_object_file(sess: &Session) -> Option { Architecture::Mips => { // copied from `mipsel-linux-gnu-gcc foo.c -c` and // inspecting the resulting `e_flags` field. - let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC; + let e_flags = elf::EF_MIPS_CPIC + | elf::EF_MIPS_PIC + | if sess.target.options.cpu.contains("r6") { + elf::EF_MIPS_ARCH_32R6 | elf::EF_MIPS_NAN2008 + } else { + elf::EF_MIPS_ARCH_32R2 + }; file.flags = FileFlags::Elf { e_flags }; } Architecture::Mips64 => { // copied from `mips64el-linux-gnuabi64-gcc foo.c -c` - let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC; + let e_flags = elf::EF_MIPS_CPIC + | elf::EF_MIPS_PIC + | if sess.target.options.cpu.contains("r6") { + elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008 + } else { + elf::EF_MIPS_ARCH_64R2 + }; file.flags = FileFlags::Elf { e_flags }; } Architecture::Riscv64 if sess.target.options.features.contains("+d") => { From 11f180f42164733cdfd65a705ee988206e9e2a5b Mon Sep 17 00:00:00 2001 From: Lain Yang Date: Fri, 7 Jan 2022 10:34:06 +0800 Subject: [PATCH 23/31] rustc_codegen_ssa: set static lifetime for object::write::Object --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 9862c3fb16eab..6849533abc049 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -95,7 +95,7 @@ fn search_for_metadata<'a>( .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e)) } -fn create_object_file(sess: &Session) -> Option { +fn create_object_file(sess: &Session) -> Option> { let endianness = match sess.target.options.endian { Endian::Little => Endianness::Little, Endian::Big => Endianness::Big, From 9a337b6fe0b9ef29bd400c00ddb29d727dca64ad Mon Sep 17 00:00:00 2001 From: Lain Yang Date: Fri, 7 Jan 2022 13:32:58 +0800 Subject: [PATCH 24/31] update Cargo.lock and gimli-rs/object for rustc_codegen_ssa --- Cargo.lock | 28 ++++++++++++++++++++++++--- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50a5d78731feb..2aa11ef5f0778 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,17 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "ahash" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom 0.2.0", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -1549,6 +1560,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "362385356d610bd1e5a408ddf8d022041774b683f345a1d2cfcb4f60f8ae2db5" dependencies = [ + "ahash", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -2349,8 +2361,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "compiler_builtins", - "crc32fast", - "indexmap", "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -2368,6 +2378,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084" +dependencies = [ + "crc32fast", + "hashbrown", + "indexmap", + "memchr", +] + [[package]] name = "odht" version = "0.3.1" @@ -3754,7 +3776,7 @@ dependencies = [ "itertools 0.9.0", "jobserver", "libc", - "object 0.26.2", + "object 0.28.1", "pathdiff", "regex", "rustc_apfloat", diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index b810e615661e0..6c6ee363ea310 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -41,6 +41,6 @@ rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } [dependencies.object] -version = "0.27.0" +version = "0.28.0" default-features = false features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"] From 72cb1bd06dfdcec7c707e46fff44b3351a6c5ea9 Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Fri, 7 Jan 2022 10:10:30 -0800 Subject: [PATCH 25/31] silence tidy errors --- library/std/src/error.rs | 14 ++++-------- library/std/src/error/tests.rs | 40 +++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 5514876c5d3b8..613ec43a906e7 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1284,9 +1284,7 @@ where for (ind, error) in cause.chain().enumerate() { writeln!(f)?; - let mut indented = Indented { - inner: f, - }; + let mut indented = Indented { inner: f }; if multiple { write!(indented, "{: >4}: {}", ind, error)?; } else { @@ -1310,8 +1308,7 @@ where } } -impl Report> -{ +impl Report> { fn backtrace(&self) -> Option<&Backtrace> { // have to grab the backtrace on the first error directly since that error may not be // 'static @@ -1353,9 +1350,7 @@ impl Report> for (ind, error) in cause.chain().enumerate() { writeln!(f)?; - let mut indented = Indented { - inner: f, - }; + let mut indented = Indented { inner: f }; if multiple { write!(indented, "{: >4}: {}", ind, error)?; } else { @@ -1411,8 +1406,7 @@ where } #[unstable(feature = "error_reporter", issue = "90172")] -impl fmt::Display for Report> -{ +impl fmt::Display for Report> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } } diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index 0835e282c46c3..eae5f43ff3cfb 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -82,11 +82,13 @@ fn multi_line_formatting() { let error = SuperError { source: SuperErrorSideKick }; let report = Report::new(&error).pretty(true); let actual = report.to_string(); - let expected = String::from("\ + let expected = String::from( + "\ SuperError is here! Caused by: - SuperErrorSideKick is here!"); + SuperErrorSideKick is here!", + ); assert_eq!(expected, actual); } @@ -112,20 +114,22 @@ fn error_with_no_sources_formats_multi_line_correctly() { #[test] fn error_with_backtrace_outputs_correctly_with_one_source() { let trace = Backtrace::force_capture(); - let expected = format!("\ + let expected = format!( + "\ The source of the error Caused by: Error with backtrace Stack backtrace: -{}", trace); +{}", + trace + ); let error = GenericError::new("Error with backtrace"); let mut error = GenericError::new_with_source("The source of the error", error); error.backtrace = Some(trace); let report = Report::new(error).pretty(true).show_backtrace(true); - println!("Error: {}", report); assert_eq!(expected.trim_end(), report.to_string()); } @@ -133,7 +137,8 @@ Stack backtrace: #[test] fn error_with_backtrace_outputs_correctly_with_two_sources() { let trace = Backtrace::force_capture(); - let expected = format!("\ + let expected = format!( + "\ Error with two sources Caused by: @@ -141,14 +146,15 @@ Caused by: 1: Error with backtrace Stack backtrace: -{}", trace); +{}", + trace + ); let mut error = GenericError::new("Error with backtrace"); error.backtrace = Some(trace); let error = GenericError::new_with_source("The source of the error", error); let error = GenericError::new_with_source("Error with two sources", error); let report = Report::new(error).pretty(true).show_backtrace(true); - println!("Error: {}", report); assert_eq!(expected.trim_end(), report.to_string()); } @@ -313,11 +319,11 @@ The message Caused by: - 0: - The message - - 1: - The message + 0: \ +\n The message + \ +\n 1: \ +\n The message "; let actual = report.to_string(); @@ -399,11 +405,11 @@ line 2 Caused by: 0: line 1 - - line 2 + \ +\n line 2 1: line 1 - - line 2"; + \ +\n line 2"; let actual = report.to_string(); assert_eq!(expected, actual); From cf36c21b289b020ef42dba1e02350672c904ad4a Mon Sep 17 00:00:00 2001 From: Lain Yang Date: Sat, 8 Jan 2022 16:27:58 +0800 Subject: [PATCH 26/31] tidy: add `ahash` to permitted dep list --- src/tools/tidy/src/deps.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 4c28655bc8653..9d2aa0f21c8e1 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -73,6 +73,7 @@ const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_driver", "rustc_codegen_l const PERMITTED_DEPENDENCIES: &[&str] = &[ "addr2line", "adler", + "ahash", "aho-corasick", "annotate-snippets", "ansi_term", From c4471b0b9c9b3762c8030c44835b614f90deaf75 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 24 Dec 2021 14:34:30 +0800 Subject: [PATCH 27/31] rustc_metadata: Stop passing `CrateMetadataRef` by reference It's already a (fat) reference. Double referencing it creates lifetime issues for its methods that want to return iterators. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 196 +++++++++---------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e39ea46c0c0ca..493c815ff0115 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -218,40 +218,40 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) { } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> { +impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> { #[inline] fn blob(self) -> &'a MetadataBlob { - &self.blob + &self.cdata.blob } #[inline] fn cdata(self) -> Option> { - Some(*self) + Some(self) } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) { #[inline] fn blob(self) -> &'a MetadataBlob { - &self.0.blob + &self.0.cdata.blob } #[inline] fn cdata(self) -> Option> { - Some(*self.0) + Some(self.0) } #[inline] fn sess(self) -> Option<&'tcx Session> { - Some(&self.1) + Some(self.1) } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) { #[inline] fn blob(self) -> &'a MetadataBlob { - &self.0.blob + &self.0.cdata.blob } #[inline] fn cdata(self) -> Option> { - Some(*self.0) + Some(self.0) } #[inline] fn tcx(self) -> Option> { @@ -414,9 +414,9 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { Ok(cdata .root .syntax_contexts - .get(&cdata, id) + .get(cdata, id) .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname)) - .decode((&cdata, sess))) + .decode((cdata, sess))) }) } } @@ -442,15 +442,15 @@ impl<'a, 'tcx> Decodable> for ExpnId { let expn_data = crate_data .root .expn_data - .get(&crate_data, index) + .get(crate_data, index) .unwrap() - .decode((&crate_data, sess)); + .decode((crate_data, sess)); let expn_hash = crate_data .root .expn_hashes - .get(&crate_data, index) + .get(crate_data, index) .unwrap() - .decode((&crate_data, sess)); + .decode((crate_data, sess)); (expn_data, expn_hash) }); Ok(expn_id) @@ -706,7 +706,7 @@ impl CrateRoot<'_> { } impl<'a, 'tcx> CrateMetadataRef<'a> { - fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { + fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. let pos = self @@ -721,7 +721,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { &self.raw_proc_macros.unwrap()[pos] } - fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option { + fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option { let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?; let span = match self.root.tables.ident_span.get(self, item_index) { Some(lazy_span) => lazy_span.decode((self, sess)), @@ -737,15 +737,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { Some(Ident::new(name, span)) } - fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident { + fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident { self.opt_item_ident(item_index, sess).expect("no encoded ident for item") } - fn maybe_kind(&self, item_id: DefIndex) -> Option { + fn maybe_kind(self, item_id: DefIndex) -> Option { self.root.tables.kind.get(self, item_id).map(|k| k.decode(self)) } - fn kind(&self, item_id: DefIndex) -> EntryKind { + fn kind(self, item_id: DefIndex) -> EntryKind { self.maybe_kind(item_id).unwrap_or_else(|| { bug!( "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}", @@ -756,7 +756,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn def_kind(&self, item_id: DefIndex) -> DefKind { + fn def_kind(self, item_id: DefIndex) -> DefKind { self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| { bug!( "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}", @@ -767,7 +767,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn get_span(&self, index: DefIndex, sess: &Session) -> Span { + fn get_span(self, index: DefIndex, sess: &Session) -> Span { self.root .tables .span @@ -776,7 +776,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { + fn load_proc_macro(self, id: DefIndex, sess: &Session) -> SyntaxExtension { let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) { ProcMacro::CustomDerive { trait_name, attributes, client } => { let helper_attrs = @@ -807,7 +807,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { + fn get_trait_def(self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { match self.kind(item_id) { EntryKind::Trait(data) => { let data = data.decode((self, sess)); @@ -837,7 +837,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_variant( - &self, + self, kind: &EntryKind, index: DefIndex, parent_did: DefId, @@ -886,7 +886,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef { + fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef { let kind = self.kind(item_id); let did = self.local_def_id(item_id); @@ -914,7 +914,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_explicit_predicates( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { @@ -922,7 +922,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_inferred_outlives( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { @@ -935,7 +935,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_super_predicates( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> ty::GenericPredicates<'tcx> { @@ -943,7 +943,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_explicit_item_bounds( - &self, + self, item_id: DefIndex, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ty::Predicate<'tcx>, Span)] { @@ -955,11 +955,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .unwrap_or_default() } - fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics { + fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics { self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess)) } - fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + fn get_type(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { self.root .tables .ty @@ -968,63 +968,63 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_stability(&self, id: DefIndex) -> Option { + fn get_stability(self, id: DefIndex) -> Option { self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)) } - fn get_const_stability(&self, id: DefIndex) -> Option { + fn get_const_stability(self, id: DefIndex) -> Option { self.root.tables.const_stability.get(self, id).map(|stab| stab.decode(self)) } - fn get_deprecation(&self, id: DefIndex) -> Option { + fn get_deprecation(self, id: DefIndex) -> Option { self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self)) } - fn get_visibility(&self, id: DefIndex) -> ty::Visibility { + fn get_visibility(self, id: DefIndex) -> ty::Visibility { self.root.tables.visibility.get(self, id).unwrap().decode(self) } - fn get_impl_data(&self, id: DefIndex) -> ImplData { + fn get_impl_data(self, id: DefIndex) -> ImplData { match self.kind(id) { EntryKind::Impl(data) => data.decode(self), _ => bug!(), } } - fn get_parent_impl(&self, id: DefIndex) -> Option { + fn get_parent_impl(self, id: DefIndex) -> Option { self.get_impl_data(id).parent_impl } - fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity { + fn get_impl_polarity(self, id: DefIndex) -> ty::ImplPolarity { self.get_impl_data(id).polarity } - fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness { + fn get_impl_defaultness(self, id: DefIndex) -> hir::Defaultness { self.get_impl_data(id).defaultness } - fn get_impl_constness(&self, id: DefIndex) -> hir::Constness { + fn get_impl_constness(self, id: DefIndex) -> hir::Constness { self.get_impl_data(id).constness } - fn get_trait_item_def_id(&self, id: DefIndex) -> Option { + fn get_trait_item_def_id(self, id: DefIndex) -> Option { self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self)) } - fn get_coerce_unsized_info(&self, id: DefIndex) -> Option { + fn get_coerce_unsized_info(self, id: DefIndex) -> Option { self.get_impl_data(id).coerce_unsized_info } - fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option> { + fn get_impl_trait(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option> { self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx))) } - fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId { + fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId { self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess)) } fn get_const_param_default( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> rustc_middle::ty::Const<'tcx> { @@ -1032,14 +1032,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over all the stability attributes in the given crate. - fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option)] { + fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option)] { // FIXME: For a proc macro crate, not sure whether we should return the "host" // features or an empty Vec. Both don't cause ICEs. tcx.arena.alloc_from_iter(self.root.lib_features.decode(self)) } /// Iterates over the language items in the given crate. - fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { + fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { if self.root.is_proc_macro_crate() { // Proc macro crates do not export any lang-items to the target. &[] @@ -1054,7 +1054,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over the diagnostic items in the given crate. - fn get_diagnostic_items(&self) -> DiagnosticItems { + fn get_diagnostic_items(self) -> DiagnosticItems { if self.root.is_proc_macro_crate() { // Proc macro crates do not export any diagnostic-items to the target. Default::default() @@ -1079,7 +1079,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { /// Module here is understood in name resolution sense - it can be a `mod` item, /// or a crate root, or an enum, or a trait. fn for_each_module_child( - &self, + self, id: DefIndex, mut callback: impl FnMut(ModChild), sess: &Session, @@ -1177,15 +1177,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn is_ctfe_mir_available(&self, id: DefIndex) -> bool { + fn is_ctfe_mir_available(self, id: DefIndex) -> bool { self.root.tables.mir_for_ctfe.get(self, id).is_some() } - fn is_item_mir_available(&self, id: DefIndex) -> bool { + fn is_item_mir_available(self, id: DefIndex) -> bool { self.root.tables.mir.get(self, id).is_some() } - fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId { + fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId { match self.kind(id) { EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => { self.get_expn_that_defined(id, sess) @@ -1194,7 +1194,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { + fn get_optimized_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { self.root .tables .mir @@ -1205,7 +1205,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { + fn get_mir_for_ctfe(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { self.root .tables .mir_for_ctfe @@ -1217,7 +1217,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_thir_abstract_const( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> Result]>, ErrorReported> { @@ -1228,7 +1228,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } - fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { + fn get_unused_generic_params(self, id: DefIndex) -> FiniteBitSet { self.root .tables .unused_generic_params @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .unwrap_or_default() } - fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec> { + fn get_promoted_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec> { self.root .tables .promoted_mir @@ -1248,7 +1248,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs { + fn mir_const_qualif(self, id: DefIndex) -> mir::ConstQualifs { match self.kind(id) { EntryKind::AnonConst(qualif, _) | EntryKind::Const(qualif, _) @@ -1263,14 +1263,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_fn_has_self_parameter(&self, id: DefIndex) -> bool { + fn get_fn_has_self_parameter(self, id: DefIndex) -> bool { match self.kind(id) { EntryKind::AssocFn(data) => data.decode(self).has_self, _ => false, } } - fn get_associated_item_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] { + fn get_associated_item_def_ids(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] { if let Some(children) = self.root.tables.children.get(self, id) { tcx.arena.alloc_from_iter( children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)), @@ -1280,7 +1280,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem { + fn get_associated_item(self, id: DefIndex, sess: &Session) -> ty::AssocItem { let def_key = self.def_key(id); let parent = self.local_def_id(def_key.parent.unwrap()); let ident = self.item_ident(id, sess); @@ -1307,11 +1307,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_item_variances(&'a self, id: DefIndex) -> impl Iterator + 'a { + fn get_item_variances(self, id: DefIndex) -> impl Iterator + 'a { self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self) } - fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { + fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { match self.kind(node_id) { EntryKind::Struct(data, _) | EntryKind::Variant(data) => { let vdata = data.decode(self); @@ -1322,7 +1322,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_item_attrs( - &'a self, + self, id: DefIndex, sess: &'a Session, ) -> impl Iterator + 'a { @@ -1346,7 +1346,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec> { + fn get_struct_field_names(self, id: DefIndex, sess: &Session) -> Vec> { self.root .tables .children @@ -1357,7 +1357,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .collect() } - fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec { + fn get_struct_field_visibilities(self, id: DefIndex) -> Vec { self.root .tables .children @@ -1369,7 +1369,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_inherent_implementations_for_type( - &self, + self, tcx: TyCtxt<'tcx>, id: DefIndex, ) -> &'tcx [DefId] { @@ -1384,20 +1384,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_traits(&'a self) -> impl Iterator + 'a { - self.root.traits.decode(self).map(|index| self.local_def_id(index)) + fn get_traits(self) -> impl Iterator + 'a { + self.root.traits.decode(self).map(move |index| self.local_def_id(index)) } - fn get_trait_impls(&'a self) -> impl Iterator)> + 'a { - self.trait_impls.values().flat_map(move |impls| { + fn get_trait_impls(self) -> impl Iterator)> + 'a { + self.cdata.trait_impls.values().flat_map(move |impls| { impls .decode(self) - .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) + .map(move |(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) }) } fn get_implementations_of_trait( - &self, + self, tcx: TyCtxt<'tcx>, trait_def_id: DefId, ) -> &'tcx [(DefId, Option)] { @@ -1424,7 +1424,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_trait_of_item(&self, id: DefIndex) -> Option { + fn get_trait_of_item(self, id: DefIndex) -> Option { let def_key = self.def_key(id); match def_key.disambiguated_data.data { DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (), @@ -1437,7 +1437,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn get_native_libraries(&self, sess: &Session) -> Vec { + fn get_native_libraries(self, sess: &Session) -> Vec { if self.root.is_proc_macro_crate() { // Proc macro crates do not have any *target* native libraries. vec![] @@ -1446,7 +1446,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_proc_macro_quoted_span(&self, index: usize, sess: &Session) -> Span { + fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span { self.root .tables .proc_macro_quoted_spans @@ -1455,7 +1455,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc> { + fn get_foreign_modules(self, tcx: TyCtxt<'tcx>) -> Lrc> { if self.root.is_proc_macro_crate() { // Proc macro crates do not have any *target* foreign modules. Lrc::new(FxHashMap::default()) @@ -1467,7 +1467,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_dylib_dependency_formats( - &self, + self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(CrateNum, LinkagePreference)] { tcx.arena.alloc_from_iter( @@ -1478,7 +1478,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { + fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { if self.root.is_proc_macro_crate() { // Proc macro crates do not depend on any target weak lang-items. &[] @@ -1487,7 +1487,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] { + fn get_fn_param_names(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] { let param_names = match self.kind(id) { EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names, EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names, @@ -1497,7 +1497,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn exported_symbols( - &self, + self, tcx: TyCtxt<'tcx>, ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] { if self.root.is_proc_macro_crate() { @@ -1509,7 +1509,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_rendered_const(&self, id: DefIndex) -> String { + fn get_rendered_const(self, id: DefIndex) -> String { match self.kind(id) { EntryKind::AnonConst(_, data) | EntryKind::Const(_, data) @@ -1518,7 +1518,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_macro(&self, id: DefIndex, sess: &Session) -> MacroDef { + fn get_macro(self, id: DefIndex, sess: &Session) -> MacroDef { match self.kind(id) { EntryKind::MacroDef(macro_def) => macro_def.decode((self, sess)), _ => bug!(), @@ -1527,7 +1527,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // This replicates some of the logic of the crate-local `is_const_fn_raw` query, because we // don't serialize constness for tuple variant and tuple struct constructors. - fn is_const_fn_raw(&self, id: DefIndex) -> bool { + fn is_const_fn_raw(self, id: DefIndex) -> bool { let constness = match self.kind(id) { EntryKind::AssocFn(data) => data.decode(self).fn_data.constness, EntryKind::Fn(data) => data.decode(self).constness, @@ -1538,7 +1538,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { constness == hir::Constness::Const } - fn asyncness(&self, id: DefIndex) -> hir::IsAsync { + fn asyncness(self, id: DefIndex) -> hir::IsAsync { match self.kind(id) { EntryKind::Fn(data) => data.decode(self).asyncness, EntryKind::AssocFn(data) => data.decode(self).fn_data.asyncness, @@ -1547,7 +1547,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn is_foreign_item(&self, id: DefIndex) -> bool { + fn is_foreign_item(self, id: DefIndex) -> bool { match self.kind(id) { EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => { true @@ -1556,7 +1556,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn static_mutability(&self, id: DefIndex) -> Option { + fn static_mutability(self, id: DefIndex) -> Option { match self.kind(id) { EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Some(hir::Mutability::Not), EntryKind::MutStatic | EntryKind::ForeignMutStatic => Some(hir::Mutability::Mut), @@ -1564,19 +1564,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn generator_kind(&self, id: DefIndex) -> Option { + fn generator_kind(self, id: DefIndex) -> Option { match self.kind(id) { EntryKind::Generator(data) => Some(data), _ => None, } } - fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { + fn fn_sig(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { self.root.tables.fn_sig.get(self, id).unwrap().decode((self, tcx)) } #[inline] - fn def_key(&self, index: DefIndex) -> DefKey { + fn def_key(self, index: DefIndex) -> DefKey { *self .def_key_cache .lock() @@ -1585,13 +1585,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } // Returns the path leading to the thing with this `id`. - fn def_path(&self, id: DefIndex) -> DefPath { + fn def_path(self, id: DefIndex) -> DefPath { debug!("def_path(cnum={:?}, id={:?})", self.cnum, id); DefPath::make(self.cnum, id, |parent| self.def_key(parent)) } fn def_path_hash_unlocked( - &self, + self, index: DefIndex, def_path_hashes: &mut FxHashMap, ) -> DefPathHash { @@ -1601,17 +1601,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } #[inline] - fn def_path_hash(&self, index: DefIndex) -> DefPathHash { + fn def_path_hash(self, index: DefIndex) -> DefPathHash { let mut def_path_hashes = self.def_path_hash_cache.lock(); self.def_path_hash_unlocked(index, &mut def_path_hashes) } #[inline] - fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex { + fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex { self.def_path_hash_map.def_path_hash_to_def_index(&hash) } - fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId { + fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId { debug_assert_eq!(ExpnId::from_hash(hash), None); let index_guess = ExpnIndex::from_u32(index_guess); let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self)); @@ -1669,7 +1669,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { /// /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. - fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] { + fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] { // Translate the virtual `/rustc/$hash` prefix back to a real directory // that should hold actual sources, where possible. // From e9cac4ca627a4da45d24ca7341bb7c66aa59cbe2 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 10 Jan 2022 09:55:52 -0500 Subject: [PATCH 28/31] Ignore `unused_mod.rs` file in code coverage results As discussed in https://github.com/rust-lang/rust/pull/92142#issuecomment-1008239473, tests that contain multiple files order their results differently on Windows and Linux which the test runner currently can't handle correctly. For now, ignore the "bin" part of the test and only include the unused library dependency which is what the test really cares about anyway. --- src/test/run-make-fulldeps/coverage-reports/Makefile | 2 +- .../expected_show_coverage.unused_mod.txt | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index 9122e0406c2ef..094d6b3ebf5f8 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -64,7 +64,7 @@ endif # if and when we allow `llvm-cov` to produce results for multiple files. Note, the path separators # appear to be normalized to `/` in those files, thankfully.) LLVM_COV_IGNORE_FILES=\ - --ignore-filename-regex='(uses_crate.rs|uses_inline_crate.rs)' + --ignore-filename-regex='(uses_crate.rs|uses_inline_crate.rs|unused_mod.rs)' all: $(patsubst $(SOURCEDIR)/lib/%.rs,%,$(wildcard $(SOURCEDIR)/lib/*.rs)) $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt index d902b7a412f3b..82d6fccc2714a 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt @@ -1,13 +1,4 @@ -../coverage/lib/unused_mod_helper.rs: 1| 0|pub fn never_called_function() { 2| 0| println!("I am never called"); 3| 0|} -../coverage/unused_mod.rs: - 1| |#[path = "lib/unused_mod_helper.rs"] - 2| |mod unused_module; - 3| | - 4| 1|fn main() { - 5| 1| println!("hello world!"); - 6| 1|} - From 4193f2da2d3553162af383dbeaf5f8ef5908dafd Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 8 Dec 2021 20:09:17 -0500 Subject: [PATCH 29/31] rustdoc: do not emit tuple variant fields if none are documented --- src/librustdoc/html/render/print_item.rs | 19 ++++++++++++++----- src/test/rustdoc/issue-88600.rs | 5 +++-- src/test/rustdoc/tuple-struct-fields-doc.rs | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 9f2830ba54215..f954123067700 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1133,18 +1133,27 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum w.write_str(""); use crate::clean::Variant; - if let Some((extra, fields)) = match *variant.kind { - clean::VariantItem(Variant::Struct(ref s)) => Some(("", &s.fields)), - clean::VariantItem(Variant::Tuple(ref fields)) => Some(("Tuple ", fields)), + + let heading_and_fields = match &*variant.kind { + clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)), + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + clean::VariantItem(Variant::Tuple(fields)) + if fields.iter().any(|f| f.doc_value().is_some()) => + { + Some(("Tuple Fields", fields)) + } _ => None, - } { + }; + + if let Some((heading, fields)) = heading_and_fields { let variant_id = cx.derive_id(format!( "{}.{}.fields", ItemType::Variant, variant.name.as_ref().unwrap() )); write!(w, "
", id = variant_id); - write!(w, "

{extra}Fields

", extra = extra,); + write!(w, "

{heading}

", heading = heading); document_non_exhaustive(w, variant); for field in fields { match *field.kind { diff --git a/src/test/rustdoc/issue-88600.rs b/src/test/rustdoc/issue-88600.rs index 3761805b48b71..fc63ed343bda2 100644 --- a/src/test/rustdoc/issue-88600.rs +++ b/src/test/rustdoc/issue-88600.rs @@ -18,17 +18,18 @@ pub enum FooEnum { // @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)' // @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0 // @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S' - MixedHiddenFirst(#[doc(hidden)] H, S), + MixedHiddenFirst(#[doc(hidden)] H, /** dox */ S), // @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)' // @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S' // @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0 - MixedHiddenLast(S, #[doc(hidden)] H), + MixedHiddenLast(/** dox */ S, #[doc(hidden)] H), // @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct' // @count - '//*[@id="variant.HiddenStruct.field.h"]' 0 // @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S' HiddenStruct { #[doc(hidden)] h: H, + /// dox s: S, }, } diff --git a/src/test/rustdoc/tuple-struct-fields-doc.rs b/src/test/rustdoc/tuple-struct-fields-doc.rs index 2e339fe82649d..31426131bc2c1 100644 --- a/src/test/rustdoc/tuple-struct-fields-doc.rs +++ b/src/test/rustdoc/tuple-struct-fields-doc.rs @@ -24,6 +24,9 @@ pub struct Foo( // @has - '//*[@id="variant.BarVariant.field.0"]' '0: String' // @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs' // @matches - '//*[@id="variant.FooVariant.fields"]/h4' '^Fields$' +// @has - '//*[@id="variant.BazVariant.fields"]//*[@class="docblock"]' 'dox' +// @has - '//*[@id="variant.OtherVariant.fields"]//*[@class="docblock"]' 'dox' +// @!matches - '//*[@id="variant.QuuxVariant.fields"]/h4' '^Tuple Fields$' pub enum Bar { BarVariant( /// Hello docs @@ -33,4 +36,15 @@ pub enum Bar { /// hello x: u32, }, + BazVariant( + String, + /// dox + u32, + ), + OtherVariant( + /// dox + String, + u32, + ), + QuuxVariant(String), } From 66f1e322c66e8278d0aba8569878cebadbcbed17 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 11 Jan 2022 20:18:29 -0800 Subject: [PATCH 30/31] Update cargo --- Cargo.lock | 54 ++++++++++++++++++++++++++++++++++++++++--------- src/tools/cargo | 2 +- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50a5d78731feb..cc5de56aaa778 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -283,7 +283,7 @@ dependencies = [ "cargo-test-macro", "cargo-test-support", "cargo-util", - "clap", + "clap 3.0.6", "crates-io", "crossbeam-utils 0.8.3", "curl", @@ -563,13 +563,28 @@ dependencies = [ "ansi_term 0.12.1", "atty", "bitflags", - "strsim", - "textwrap", + "strsim 0.8.0", + "textwrap 0.11.0", "unicode-width", "vec_map", "yaml-rust 0.3.5", ] +[[package]] +name = "clap" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0" +dependencies = [ + "atty", + "bitflags", + "indexmap", + "os_str_bytes", + "strsim 0.10.0", + "termcolor", + "textwrap 0.14.2", +] + [[package]] name = "clippy" version = "0.1.59" @@ -600,7 +615,7 @@ version = "0.0.1" dependencies = [ "bytecount", "cargo_metadata 0.14.0", - "clap", + "clap 2.34.0", "indoc", "itertools 0.10.1", "opener", @@ -1716,7 +1731,7 @@ name = "installer" version = "0.0.0" dependencies = [ "anyhow", - "clap", + "clap 2.34.0", "flate2", "lazy_static", "num_cpus", @@ -2161,7 +2176,7 @@ dependencies = [ "ammonia", "anyhow", "chrono", - "clap", + "clap 2.34.0", "elasticlunr-rs", "env_logger 0.7.1", "handlebars", @@ -2465,6 +2480,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + [[package]] name = "output_vt100" version = "0.1.2" @@ -2869,7 +2893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb" dependencies = [ "bitflags", - "clap", + "clap 2.34.0", "derive_more", "env_logger 0.7.1", "humantime 2.0.1", @@ -3224,7 +3248,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap", + "clap 2.34.0", "env_logger 0.7.1", "mdbook", ] @@ -5086,13 +5110,19 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "structopt" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" dependencies = [ - "clap", + "clap 2.34.0", "lazy_static", "structopt-derive", ] @@ -5278,6 +5308,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + [[package]] name = "thiserror" version = "1.0.30" diff --git a/src/tools/cargo b/src/tools/cargo index 358e79fe56fe3..06b9d31743210 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 358e79fe56fe374649275ca7aebaafd57ade0e8d +Subproject commit 06b9d31743210b788b130c8a484c2838afa6fc27 From 5b2d5da0d3c913e0b38ea432af34375e903752aa Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 12 Jan 2022 16:05:30 -0800 Subject: [PATCH 31/31] Update RELEASES for 1.58. --- RELEASES.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 01c57ab917033..fc0a5d35f30f3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -43,7 +43,6 @@ Stabilized APIs - [`Option::unwrap_unchecked`] - [`Result::unwrap_unchecked`] - [`Result::unwrap_err_unchecked`] -- [`NonZero{unsigned}::is_power_of_two`] - [`File::options`] These APIs are now usable in const contexts: @@ -56,10 +55,6 @@ These APIs are now usable in const contexts: - [`Duration::checked_mul`] - [`Duration::saturating_mul`] - [`Duration::checked_div`] -- [`MaybeUninit::as_ptr`] -- [`MaybeUninit::as_mut_ptr`] -- [`MaybeUninit::assume_init`] -- [`MaybeUninit::assume_init_ref`] Cargo ----- @@ -141,7 +136,6 @@ and related tools. [`Option::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_unchecked [`Result::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_unchecked [`Result::unwrap_err_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_err_unchecked -[`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two [`File::options`]: https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.options [`unix::process::ExitStatusExt::core_dumped`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.core_dumped [`unix::process::ExitStatusExt::stopped_signal`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.stopped_signal @@ -165,10 +159,6 @@ and related tools. [`Duration::div_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f32 [`Duration::div_duration_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f64 [`Duration::div_duration_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f32 -[`MaybeUninit::as_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_ptr -[`MaybeUninit::as_mut_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_mut_ptr -[`MaybeUninit::assume_init`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init -[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref Version 1.57.0 (2021-12-02) ==========================