mirror of https://github.com/rust-lang/rust.git
Auto merge of #64281 - Centril:rollup-inyqjf8, r=Centril
Rollup of 4 pull requests Successful merges: - #62205 (Add Iterator comparison methods that take a comparison function) - #64152 (Use backtrace formatting from the backtrace crate) - #64265 (resolve: Mark more erroneous imports as used) - #64267 (rustdoc: fix diagnostic with mixed code block styles) Failed merges: r? @ghost
This commit is contained in:
commit
2c0931e168
|
@ -109,9 +109,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.35"
|
||||
version = "0.3.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55"
|
||||
checksum = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2"
|
||||
dependencies = [
|
||||
"backtrace-sys",
|
||||
"cfg-if",
|
||||
|
|
|
@ -2557,10 +2557,40 @@ pub trait Iterator {
|
|||
/// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater);
|
||||
/// ```
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn cmp<I>(mut self, other: I) -> Ordering where
|
||||
fn cmp<I>(self, other: I) -> Ordering
|
||||
where
|
||||
I: IntoIterator<Item = Self::Item>,
|
||||
Self::Item: Ord,
|
||||
Self: Sized,
|
||||
{
|
||||
self.cmp_by(other, |x, y| x.cmp(&y))
|
||||
}
|
||||
|
||||
/// Lexicographically compares the elements of this `Iterator` with those
|
||||
/// of another with respect to the specified comparison function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_order_by)]
|
||||
///
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let xs = [1, 2, 3, 4];
|
||||
/// let ys = [1, 4, 9, 16];
|
||||
///
|
||||
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| x.cmp(&y)), Ordering::Less);
|
||||
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal);
|
||||
/// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater);
|
||||
/// ```
|
||||
#[unstable(feature = "iter_order_by", issue = "0")]
|
||||
fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> Ordering
|
||||
where
|
||||
Self: Sized,
|
||||
I: IntoIterator,
|
||||
F: FnMut(Self::Item, I::Item) -> Ordering,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
|
@ -2579,7 +2609,7 @@ pub trait Iterator {
|
|||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.cmp(&y) {
|
||||
match cmp(x, y) {
|
||||
Ordering::Equal => (),
|
||||
non_eq => return non_eq,
|
||||
}
|
||||
|
@ -2601,10 +2631,49 @@ pub trait Iterator {
|
|||
/// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None);
|
||||
/// ```
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn partial_cmp<I>(mut self, other: I) -> Option<Ordering> where
|
||||
fn partial_cmp<I>(self, other: I) -> Option<Ordering>
|
||||
where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialOrd<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
self.partial_cmp_by(other, |x, y| x.partial_cmp(&y))
|
||||
}
|
||||
|
||||
/// Lexicographically compares the elements of this `Iterator` with those
|
||||
/// of another with respect to the specified comparison function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_order_by)]
|
||||
///
|
||||
/// use std::cmp::Ordering;
|
||||
///
|
||||
/// let xs = [1.0, 2.0, 3.0, 4.0];
|
||||
/// let ys = [1.0, 4.0, 9.0, 16.0];
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// xs.iter().partial_cmp_by(&ys, |&x, &y| x.partial_cmp(&y)),
|
||||
/// Some(Ordering::Less)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// xs.iter().partial_cmp_by(&ys, |&x, &y| (x * x).partial_cmp(&y)),
|
||||
/// Some(Ordering::Equal)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// xs.iter().partial_cmp_by(&ys, |&x, &y| (2.0 * x).partial_cmp(&y)),
|
||||
/// Some(Ordering::Greater)
|
||||
/// );
|
||||
/// ```
|
||||
#[unstable(feature = "iter_order_by", issue = "0")]
|
||||
fn partial_cmp_by<I, F>(mut self, other: I, mut partial_cmp: F) -> Option<Ordering>
|
||||
where
|
||||
Self: Sized,
|
||||
I: IntoIterator,
|
||||
F: FnMut(Self::Item, I::Item) -> Option<Ordering>,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
|
@ -2623,7 +2692,7 @@ pub trait Iterator {
|
|||
Some(val) => val,
|
||||
};
|
||||
|
||||
match x.partial_cmp(&y) {
|
||||
match partial_cmp(x, y) {
|
||||
Some(Ordering::Equal) => (),
|
||||
non_eq => return non_eq,
|
||||
}
|
||||
|
@ -2640,10 +2709,36 @@ pub trait Iterator {
|
|||
/// assert_eq!([1].iter().eq([1, 2].iter()), false);
|
||||
/// ```
|
||||
#[stable(feature = "iter_order", since = "1.5.0")]
|
||||
fn eq<I>(mut self, other: I) -> bool where
|
||||
fn eq<I>(self, other: I) -> bool
|
||||
where
|
||||
I: IntoIterator,
|
||||
Self::Item: PartialEq<I::Item>,
|
||||
Self: Sized,
|
||||
{
|
||||
self.eq_by(other, |x, y| x == y)
|
||||
}
|
||||
|
||||
/// Determines if the elements of this `Iterator` are equal to those of
|
||||
/// another with respect to the specified equality function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_order_by)]
|
||||
///
|
||||
/// let xs = [1, 2, 3, 4];
|
||||
/// let ys = [1, 4, 9, 16];
|
||||
///
|
||||
/// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y));
|
||||
/// ```
|
||||
#[unstable(feature = "iter_order_by", issue = "0")]
|
||||
fn eq_by<I, F>(mut self, other: I, mut eq: F) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
I: IntoIterator,
|
||||
F: FnMut(Self::Item, I::Item) -> bool,
|
||||
{
|
||||
let mut other = other.into_iter();
|
||||
|
||||
|
@ -2658,7 +2753,9 @@ pub trait Iterator {
|
|||
Some(val) => val,
|
||||
};
|
||||
|
||||
if x != y { return false }
|
||||
if !eq(x, y) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,62 @@ fn test_multi_iter() {
|
|||
assert!(xs.iter().lt(xs.iter().skip(2)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cmp_by() {
|
||||
use core::cmp::Ordering;
|
||||
|
||||
let f = |x: i32, y: i32| (x * x).cmp(&y);
|
||||
let xs = || [1, 2, 3, 4].iter().copied();
|
||||
let ys = || [1, 4, 16].iter().copied();
|
||||
|
||||
assert_eq!(xs().cmp_by(ys(), f), Ordering::Less);
|
||||
assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater);
|
||||
assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal);
|
||||
assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater);
|
||||
assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less);
|
||||
assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_partial_cmp_by() {
|
||||
use core::cmp::Ordering;
|
||||
use core::f64;
|
||||
|
||||
let f = |x: i32, y: i32| (x * x).partial_cmp(&y);
|
||||
let xs = || [1, 2, 3, 4].iter().copied();
|
||||
let ys = || [1, 4, 16].iter().copied();
|
||||
|
||||
assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less));
|
||||
assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
|
||||
assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal));
|
||||
assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater));
|
||||
assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less));
|
||||
assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater));
|
||||
|
||||
let f = |x: f64, y: f64| (x * x).partial_cmp(&y);
|
||||
let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied();
|
||||
let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied();
|
||||
|
||||
assert_eq!(xs().partial_cmp_by(ys(), f), None);
|
||||
assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq_by() {
|
||||
let f = |x: i32, y: i32| x * x == y;
|
||||
let xs = || [1, 2, 3, 4].iter().copied();
|
||||
let ys = || [1, 4, 9, 16].iter().copied();
|
||||
|
||||
assert!(xs().eq_by(ys(), f));
|
||||
assert!(!ys().eq_by(xs(), f));
|
||||
assert!(!xs().eq_by(xs(), f));
|
||||
assert!(!ys().eq_by(ys(), f));
|
||||
|
||||
assert!(!xs().take(3).eq_by(ys(), f));
|
||||
assert!(!xs().eq_by(ys().take(3), f));
|
||||
assert!(xs().take(3).eq_by(ys().take(3), f));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_counter_from_iter() {
|
||||
let it = (0..).step_by(5).take(10);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#![feature(const_fn)]
|
||||
#![feature(iter_partition_in_place)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(iter_order_by)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
|
|
|
@ -673,6 +673,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
self.throw_unresolved_import_error(errors.clone(), None);
|
||||
}
|
||||
|
||||
for import in &self.r.indeterminate_imports {
|
||||
// Consider erroneous imports used to avoid duplicate diagnostics.
|
||||
self.r.used_imports.insert((import.id, TypeNS));
|
||||
}
|
||||
// Report unresolved imports only if no hard error was already reported
|
||||
// to avoid generating multiple errors on the same import.
|
||||
if !has_errors {
|
||||
|
@ -839,6 +843,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
true, directive.span, directive.crate_lint());
|
||||
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
|
||||
directive.vis.set(orig_vis);
|
||||
if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
|
||||
// Consider erroneous imports used to avoid duplicate diagnostics.
|
||||
self.r.used_imports.insert((directive.id, TypeNS));
|
||||
}
|
||||
let module = match path_res {
|
||||
PathResult::Module(module) => {
|
||||
// Consistency checks, analogous to `finalize_macro_resolutions`.
|
||||
|
|
|
@ -931,7 +931,10 @@ crate fn rust_code_blocks(md: &str) -> Vec<RustCodeBlock> {
|
|||
is_fenced = true;
|
||||
previous_offset + fence_idx
|
||||
}
|
||||
None => offset,
|
||||
None => {
|
||||
is_fenced = false;
|
||||
offset
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ unwind = { path = "../libunwind" }
|
|||
hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.35"
|
||||
version = "0.3.37"
|
||||
default-features = false # don't use coresymbolication on OSX
|
||||
features = [
|
||||
"rustc-dep-of-std", # enable build support for integrating into libstd
|
||||
|
|
|
@ -158,7 +158,7 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
|
|||
|
||||
fn default_hook(info: &PanicInfo<'_>) {
|
||||
#[cfg(feature = "backtrace")]
|
||||
use crate::sys_common::backtrace;
|
||||
use crate::sys_common::{backtrace as backtrace_mod};
|
||||
|
||||
// If this is a double panic, make sure that we print a backtrace
|
||||
// for this panic. Otherwise only print it if logging is enabled.
|
||||
|
@ -167,9 +167,9 @@ fn default_hook(info: &PanicInfo<'_>) {
|
|||
let panics = update_panic_count(0);
|
||||
|
||||
if panics >= 2 {
|
||||
Some(backtrace::PrintFormat::Full)
|
||||
Some(backtrace::PrintFmt::Full)
|
||||
} else {
|
||||
backtrace::log_enabled()
|
||||
backtrace_mod::log_enabled()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -197,7 +197,7 @@ fn default_hook(info: &PanicInfo<'_>) {
|
|||
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
if let Some(format) = log_backtrace {
|
||||
let _ = backtrace::print(err, format);
|
||||
let _ = backtrace_mod::print(err, format);
|
||||
} else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
|
||||
let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \
|
||||
environment variable to display a backtrace.");
|
||||
|
|
|
@ -2,23 +2,20 @@
|
|||
/// supported platforms.
|
||||
|
||||
use crate::env;
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::io::prelude::*;
|
||||
use crate::mem;
|
||||
use crate::path::{self, Path};
|
||||
use crate::ptr;
|
||||
use crate::sync::atomic::{self, Ordering};
|
||||
use crate::sys::mutex::Mutex;
|
||||
|
||||
use backtrace::{BytesOrWideString, Frame, Symbol};
|
||||
|
||||
pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::<usize>();
|
||||
use backtrace::{BacktraceFmt, BytesOrWideString, PrintFmt};
|
||||
|
||||
/// Max number of frames to print.
|
||||
const MAX_NB_FRAMES: usize = 100;
|
||||
|
||||
/// Prints the current backtrace.
|
||||
pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
|
||||
pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
|
||||
static LOCK: Mutex = Mutex::new();
|
||||
|
||||
// There are issues currently linking libbacktrace into tests, and in
|
||||
|
@ -39,26 +36,66 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
|
||||
writeln!(w, "stack backtrace:")?;
|
||||
fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
|
||||
struct DisplayBacktrace {
|
||||
format: PrintFmt,
|
||||
}
|
||||
impl fmt::Display for DisplayBacktrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
_print_fmt(fmt, self.format)
|
||||
}
|
||||
}
|
||||
write!(w, "{}", DisplayBacktrace { format })
|
||||
}
|
||||
|
||||
let mut printer = Printer::new(format, w);
|
||||
fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
|
||||
let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
|
||||
output_filename(fmt, bows, print_fmt)
|
||||
};
|
||||
let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
|
||||
bt_fmt.add_context()?;
|
||||
let mut skipped = false;
|
||||
unsafe {
|
||||
let mut idx = 0;
|
||||
let mut res = Ok(());
|
||||
backtrace::trace_unsynchronized(|frame| {
|
||||
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
|
||||
skipped = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut hit = false;
|
||||
let mut stop = false;
|
||||
backtrace::resolve_frame_unsynchronized(frame, |symbol| {
|
||||
hit = true;
|
||||
printer.output(frame, Some(symbol));
|
||||
if print_fmt == PrintFmt::Short {
|
||||
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
|
||||
if sym.contains("__rust_begin_short_backtrace") {
|
||||
skipped = true;
|
||||
stop = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res = bt_fmt.frame().symbol(frame, symbol);
|
||||
});
|
||||
if !hit {
|
||||
printer.output(frame, None);
|
||||
if stop {
|
||||
return false;
|
||||
}
|
||||
!printer.done
|
||||
if !hit {
|
||||
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
res.is_ok()
|
||||
});
|
||||
res?;
|
||||
}
|
||||
if printer.skipped {
|
||||
bt_fmt.finish()?;
|
||||
if skipped {
|
||||
writeln!(
|
||||
w,
|
||||
fmt,
|
||||
"note: Some details are omitted, \
|
||||
run with `RUST_BACKTRACE=full` for a verbose backtrace."
|
||||
)?;
|
||||
|
@ -77,33 +114,24 @@ where
|
|||
f()
|
||||
}
|
||||
|
||||
/// Controls how the backtrace should be formatted.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum PrintFormat {
|
||||
/// Show only relevant data from the backtrace.
|
||||
Short = 2,
|
||||
/// Show all the frames with absolute path for files.
|
||||
Full = 3,
|
||||
}
|
||||
|
||||
// For now logging is turned off by default, and this function checks to see
|
||||
// whether the magical environment variable is present to see if it's turned on.
|
||||
pub fn log_enabled() -> Option<PrintFormat> {
|
||||
pub fn log_enabled() -> Option<PrintFmt> {
|
||||
static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
|
||||
match ENABLED.load(Ordering::SeqCst) {
|
||||
0 => {}
|
||||
1 => return None,
|
||||
2 => return Some(PrintFormat::Short),
|
||||
_ => return Some(PrintFormat::Full),
|
||||
2 => return Some(PrintFmt::Short),
|
||||
_ => return Some(PrintFmt::Full),
|
||||
}
|
||||
|
||||
let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
|
||||
if &x == "0" {
|
||||
None
|
||||
} else if &x == "full" {
|
||||
Some(PrintFormat::Full)
|
||||
Some(PrintFmt::Full)
|
||||
} else {
|
||||
Some(PrintFormat::Short)
|
||||
Some(PrintFmt::Short)
|
||||
}
|
||||
});
|
||||
ENABLED.store(
|
||||
|
@ -116,130 +144,45 @@ pub fn log_enabled() -> Option<PrintFormat> {
|
|||
val
|
||||
}
|
||||
|
||||
struct Printer<'a, 'b> {
|
||||
format: PrintFormat,
|
||||
done: bool,
|
||||
skipped: bool,
|
||||
idx: usize,
|
||||
out: &'a mut (dyn Write + 'b),
|
||||
}
|
||||
|
||||
impl<'a, 'b> Printer<'a, 'b> {
|
||||
fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> {
|
||||
Printer { format, done: false, skipped: false, idx: 0, out }
|
||||
}
|
||||
|
||||
/// Prints the symbol of the backtrace frame.
|
||||
///
|
||||
/// These output functions should now be used everywhere to ensure consistency.
|
||||
/// You may want to also use `output_fileline`.
|
||||
fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) {
|
||||
if self.idx > MAX_NB_FRAMES {
|
||||
self.done = true;
|
||||
self.skipped = true;
|
||||
return;
|
||||
/// Prints the filename of the backtrace frame.
|
||||
///
|
||||
/// See also `output`.
|
||||
fn output_filename(
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
bows: BytesOrWideString<'_>,
|
||||
print_fmt: PrintFmt,
|
||||
) -> fmt::Result {
|
||||
#[cfg(windows)]
|
||||
let path_buf;
|
||||
let file = match bows {
|
||||
#[cfg(unix)]
|
||||
BytesOrWideString::Bytes(bytes) => {
|
||||
use crate::os::unix::prelude::*;
|
||||
Path::new(crate::ffi::OsStr::from_bytes(bytes))
|
||||
}
|
||||
if self._output(frame, symbol).is_err() {
|
||||
self.done = true;
|
||||
#[cfg(not(unix))]
|
||||
BytesOrWideString::Bytes(bytes) => {
|
||||
Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
|
||||
}
|
||||
self.idx += 1;
|
||||
}
|
||||
|
||||
fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> {
|
||||
if self.format == PrintFormat::Short {
|
||||
if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) {
|
||||
if sym.contains("__rust_begin_short_backtrace") {
|
||||
self.skipped = true;
|
||||
self.done = true;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the `17: 0x0 - <unknown>` line.
|
||||
if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() {
|
||||
self.skipped = true;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
match self.format {
|
||||
PrintFormat::Full => {
|
||||
write!(self.out, " {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)?
|
||||
}
|
||||
PrintFormat::Short => write!(self.out, " {:2}: ", self.idx)?,
|
||||
}
|
||||
|
||||
match symbol.and_then(|s| s.name()) {
|
||||
Some(symbol) => {
|
||||
match self.format {
|
||||
PrintFormat::Full => write!(self.out, "{}", symbol)?,
|
||||
// Strip the trailing hash if short mode.
|
||||
PrintFormat::Short => write!(self.out, "{:#}", symbol)?,
|
||||
}
|
||||
}
|
||||
None => self.out.write_all(b"<unknown>")?,
|
||||
}
|
||||
self.out.write_all(b"\n")?;
|
||||
if let Some(sym) = symbol {
|
||||
self.output_fileline(sym)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prints the filename and line number of the backtrace frame.
|
||||
///
|
||||
/// See also `output`.
|
||||
fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> {
|
||||
#[cfg(windows)]
|
||||
let path_buf;
|
||||
let file = match symbol.filename_raw() {
|
||||
#[cfg(unix)]
|
||||
Some(BytesOrWideString::Bytes(bytes)) => {
|
||||
use crate::os::unix::prelude::*;
|
||||
Path::new(crate::ffi::OsStr::from_bytes(bytes))
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
Some(BytesOrWideString::Bytes(bytes)) => {
|
||||
Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
|
||||
}
|
||||
#[cfg(windows)]
|
||||
Some(BytesOrWideString::Wide(wide)) => {
|
||||
use crate::os::windows::prelude::*;
|
||||
path_buf = crate::ffi::OsString::from_wide(wide);
|
||||
Path::new(&path_buf)
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
Some(BytesOrWideString::Wide(_wide)) => {
|
||||
Path::new("<unknown>")
|
||||
}
|
||||
None => return Ok(()),
|
||||
};
|
||||
let line = match symbol.lineno() {
|
||||
Some(line) => line,
|
||||
None => return Ok(()),
|
||||
};
|
||||
// prior line: " ##: {:2$} - func"
|
||||
self.out.write_all(b"")?;
|
||||
match self.format {
|
||||
PrintFormat::Full => write!(self.out, " {:1$}", "", HEX_WIDTH)?,
|
||||
PrintFormat::Short => write!(self.out, " ")?,
|
||||
BytesOrWideString::Wide(wide) => {
|
||||
use crate::os::windows::prelude::*;
|
||||
path_buf = crate::ffi::OsString::from_wide(wide);
|
||||
Path::new(&path_buf)
|
||||
}
|
||||
|
||||
let mut already_printed = false;
|
||||
if self.format == PrintFormat::Short && file.is_absolute() {
|
||||
if let Ok(cwd) = env::current_dir() {
|
||||
if let Ok(stripped) = file.strip_prefix(&cwd) {
|
||||
if let Some(s) = stripped.to_str() {
|
||||
write!(self.out, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
|
||||
already_printed = true;
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
BytesOrWideString::Wide(_wide) => {
|
||||
Path::new("<unknown>")
|
||||
}
|
||||
};
|
||||
if print_fmt == PrintFmt::Short && file.is_absolute() {
|
||||
if let Ok(cwd) = env::current_dir() {
|
||||
if let Ok(stripped) = file.strip_prefix(&cwd) {
|
||||
if let Some(s) = stripped.to_str() {
|
||||
return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !already_printed {
|
||||
write!(self.out, " at {}:{}", file.display(), line)?;
|
||||
}
|
||||
|
||||
self.out.write_all(b"\n")
|
||||
}
|
||||
fmt::Display::fmt(&file.display(), fmt)
|
||||
}
|
||||
|
|
|
@ -74,3 +74,11 @@ pub fn empty_rust() {}
|
|||
///
|
||||
/// ```
|
||||
pub fn empty_rust_with_whitespace() {}
|
||||
|
||||
/// ```
|
||||
/// let x = 1;
|
||||
/// ```
|
||||
///
|
||||
/// \____/
|
||||
///
|
||||
pub fn indent_after_fenced() {}
|
||||
|
|
|
@ -201,6 +201,24 @@ help: mark blocks that do not contain Rust code as text
|
|||
LL | /// ```text
|
||||
| ^^^^^^^
|
||||
|
||||
error: unknown start of token: \
|
||||
--> <doctest>:1:1
|
||||
|
|
||||
1 | \____/
|
||||
| ^
|
||||
|
||||
warning: could not parse code block as Rust code
|
||||
--> $DIR/invalid-syntax.rs:82:9
|
||||
|
|
||||
LL | /// \____/
|
||||
| ^^^^^^
|
||||
|
||||
error: unknown start of token: \
|
||||
--> <rustdoc-highlighting>:1:1
|
||||
|
|
||||
1 | \____/
|
||||
| ^
|
||||
|
||||
error: unknown start of token: \
|
||||
--> <rustdoc-highlighting>:1:1
|
||||
|
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
// There should be *no* unused import errors.
|
||||
// There should be *one* unused import error.
|
||||
#![deny(unused_imports)]
|
||||
|
||||
mod qux {
|
||||
fn quz() {}
|
||||
pub fn quy() {}
|
||||
}
|
||||
|
||||
use qux::quz; //~ ERROR function `quz` is private
|
||||
use qux::bar; //~ ERROR unresolved import `qux::bar`
|
||||
use foo::bar; //~ ERROR unresolved import `foo`
|
||||
use qux::quz; //~ ERROR function `quz` is private
|
||||
use qux::bar; //~ ERROR unresolved import `qux::bar`
|
||||
use foo::bar;
|
||||
use baz::*;
|
||||
use qux::bar2; //~ ERROR unresolved import `qux::bar2`
|
||||
use foo2::bar2;
|
||||
use baz2::*;
|
||||
use qux::quy; //~ ERROR unused import
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,22 +1,34 @@
|
|||
error[E0432]: unresolved import `qux::bar`
|
||||
--> $DIR/unresolved-imports-used.rs:9:5
|
||||
--> $DIR/unresolved-imports-used.rs:10:5
|
||||
|
|
||||
LL | use qux::bar;
|
||||
| ^^^^^^^^ no `bar` in `qux`
|
||||
|
||||
error[E0432]: unresolved import `foo`
|
||||
--> $DIR/unresolved-imports-used.rs:10:5
|
||||
error[E0432]: unresolved import `qux::bar2`
|
||||
--> $DIR/unresolved-imports-used.rs:13:5
|
||||
|
|
||||
LL | use foo::bar;
|
||||
| ^^^ maybe a missing crate `foo`?
|
||||
LL | use qux::bar2;
|
||||
| ^^^^^^^^^ no `bar2` in `qux`
|
||||
|
||||
error[E0603]: function `quz` is private
|
||||
--> $DIR/unresolved-imports-used.rs:8:10
|
||||
--> $DIR/unresolved-imports-used.rs:9:10
|
||||
|
|
||||
LL | use qux::quz;
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: unused import: `qux::quy`
|
||||
--> $DIR/unresolved-imports-used.rs:16:5
|
||||
|
|
||||
LL | use qux::quy;
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/unresolved-imports-used.rs:2:9
|
||||
|
|
||||
LL | #![deny(unused_imports)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0432, E0603.
|
||||
For more information about an error, try `rustc --explain E0432`.
|
||||
|
|
Loading…
Reference in New Issue