From 5cf3cbf3b7383f0d4b5ba6524856445a7d7aab2c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Apr 2023 19:53:16 +0200 Subject: [PATCH 01/12] Remove "V1" from ArgumentsV1 and FlagsV1. --- compiler/rustc_ast_lowering/src/format.rs | 18 ++++---- .../src/transform/check_consts/ops.rs | 2 +- compiler/rustc_span/src/symbol.rs | 3 +- library/core/src/fmt/mod.rs | 46 +++++++++---------- .../macro_expansion_tests/builtin_fn_macro.rs | 6 +-- .../crates/hir-expand/src/builtin_fn_macro.rs | 6 +-- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index ccf481cb9b3..a4605879589 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -186,7 +186,7 @@ enum ArgumentType { /// Generates: /// /// ```text -/// ::new_…(arg) +/// ::new_…(arg) /// ``` fn make_argument<'hir>( ctx: &mut LoweringContext<'_, 'hir>, @@ -327,7 +327,7 @@ fn make_format_spec<'hir>( None => sym::Unknown, }, ); - // This needs to match `FlagV1` in library/core/src/fmt/mod.rs. + // This needs to match `Flag` in library/core/src/fmt/mod.rs. let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) | ((sign == Some(FormatSign::Minus)) as u32) << 1 | (alternate as u32) << 2 @@ -438,7 +438,7 @@ fn expand_format_args<'hir>( // If the args array contains exactly all the original arguments once, // in order, we can use a simple array instead of a `match` construction. // However, if there's a yield point in any argument except the first one, - // we don't do this, because an ArgumentV1 cannot be kept across yield points. + // we don't do this, because an Argument cannot be kept across yield points. // // This is an optimization, speeding up compilation about 1-2% in some cases. // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609 @@ -449,9 +449,9 @@ fn expand_format_args<'hir>( let args = if use_simple_array { // Generate: // &[ - // ::new_display(&arg0), - // ::new_lower_hex(&arg1), - // ::new_debug(&arg2), + // ::new_display(&arg0), + // ::new_lower_hex(&arg1), + // ::new_debug(&arg2), // … // ] let elements: Vec<_> = arguments @@ -477,9 +477,9 @@ fn expand_format_args<'hir>( // Generate: // &match (&arg0, &arg1, &…) { // args => [ - // ::new_display(args.0), - // ::new_lower_hex(args.1), - // ::new_debug(args.0), + // ::new_display(args.0), + // ::new_lower_hex(args.1), + // ::new_debug(args.0), // … // ] // } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 6c11edb742c..4fb66854571 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -296,7 +296,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); err } - _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => ccx + _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => ccx .tcx .sess .create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 70b9088de50..9b4a2a0e7ff 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -129,8 +129,7 @@ symbols! { Any, Arc, Argument, - ArgumentV1, - ArgumentV1Methods, + ArgumentMethods, Arguments, AsMut, AsRef, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index a901ae72669..19d69e5c35e 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -267,7 +267,7 @@ extern "C" { #[allow(missing_debug_implementations)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[doc(hidden)] -pub struct ArgumentV1<'a> { +pub struct Argument<'a> { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, } @@ -321,18 +321,18 @@ macro_rules! arg_new { #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[inline] - pub fn $f<'b, T: $t>(x: &'b T) -> ArgumentV1<'_> { + pub fn $f<'b, T: $t>(x: &'b T) -> Argument<'_> { Self::new(x, $t::fmt) } }; } -#[rustc_diagnostic_item = "ArgumentV1Methods"] -impl<'a> ArgumentV1<'a> { +#[rustc_diagnostic_item = "ArgumentMethods"] +impl<'a> Argument<'a> { #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[inline] - pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { + pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { // SAFETY: `mem::transmute(x)` is safe because // 1. `&'b T` keeps the lifetime it originated with `'b` // (so as to not have an unbounded lifetime) @@ -341,7 +341,7 @@ impl<'a> ArgumentV1<'a> { // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result` // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI // (as long as `T` is `Sized`) - unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } } + unsafe { Argument { formatter: mem::transmute(f), value: mem::transmute(x) } } } arg_new!(new_display, Display); @@ -356,8 +356,8 @@ impl<'a> ArgumentV1<'a> { #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn from_usize(x: &usize) -> ArgumentV1<'_> { - ArgumentV1::new(x, USIZE_MARKER) + pub fn from_usize(x: &usize) -> Argument<'_> { + Argument::new(x, USIZE_MARKER) } fn as_usize(&self) -> Option { @@ -377,7 +377,7 @@ impl<'a> ArgumentV1<'a> { // flags available in the v1 format of format_args #[derive(Copy, Clone)] -enum FlagV1 { +enum Flag { SignPlus, SignMinus, Alternate, @@ -404,7 +404,7 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + pub fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { if pieces.len() < args.len() || pieces.len() > args.len() + 1 { panic!("invalid args"); } @@ -416,7 +416,7 @@ impl<'a> Arguments<'a> { #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { if pieces.len() < args.len() || pieces.len() > args.len() + 1 { panic!("invalid args"); } @@ -435,7 +435,7 @@ impl<'a> Arguments<'a> { #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] pub fn new_v1_formatted( pieces: &'a [&'static str], - args: &'a [ArgumentV1<'a>], + args: &'a [Argument<'a>], fmt: &'a [rt::Placeholder], _unsafe_arg: UnsafeArg, ) -> Arguments<'a> { @@ -502,7 +502,7 @@ pub struct Arguments<'a> { // Dynamic arguments for interpolation, to be interleaved with string // pieces. (Every argument is preceded by a string piece.) - args: &'a [ArgumentV1<'a>], + args: &'a [Argument<'a>], } impl<'a> Arguments<'a> { @@ -1274,7 +1274,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { Ok(()) } -unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[ArgumentV1<'_>]) -> Result { +unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[Argument<'_>]) -> Result { fmt.fill = arg.fill; fmt.align = arg.align; fmt.flags = arg.flags; @@ -1295,7 +1295,7 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[ArgumentV1 (value.formatter)(value.value, fmt) } -unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::Count) -> Option { +unsafe fn getcount(args: &[Argument<'_>], cnt: &rt::Count) -> Option { match *cnt { rt::Count::Is(n) => Some(n), rt::Count::Implied => None, @@ -1878,7 +1878,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.flags & (1 << FlagV1::SignPlus as u32) != 0 + self.flags & (1 << Flag::SignPlus as u32) != 0 } /// Determines if the `-` flag was specified. @@ -1907,7 +1907,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.flags & (1 << FlagV1::SignMinus as u32) != 0 + self.flags & (1 << Flag::SignMinus as u32) != 0 } /// Determines if the `#` flag was specified. @@ -1935,7 +1935,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.flags & (1 << FlagV1::Alternate as u32) != 0 + self.flags & (1 << Flag::Alternate as u32) != 0 } /// Determines if the `0` flag was specified. @@ -1961,17 +1961,17 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0 + self.flags & (1 << Flag::SignAwareZeroPad as u32) != 0 } // FIXME: Decide what public API we want for these two flags. // https://github.com/rust-lang/rust/issues/48584 fn debug_lower_hex(&self) -> bool { - self.flags & (1 << FlagV1::DebugLowerHex as u32) != 0 + self.flags & (1 << Flag::DebugLowerHex as u32) != 0 } fn debug_upper_hex(&self) -> bool { - self.flags & (1 << FlagV1::DebugUpperHex as u32) != 0 + self.flags & (1 << Flag::DebugUpperHex as u32) != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2531,13 +2531,13 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul // or not to zero extend, and then unconditionally set it to get the // prefix. if f.alternate() { - f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); + f.flags |= 1 << (Flag::SignAwareZeroPad as u32); if f.width.is_none() { f.width = Some((usize::BITS / 4) as usize + 2); } } - f.flags |= 1 << (FlagV1::Alternate as u32); + f.flags |= 1 << (Flag::Alternate as u32); let ret = LowerHex::fmt(&ptr_addr, f); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 0b72ca1eec1..5fbd1789b3a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -201,7 +201,7 @@ macro_rules! format_args { } fn main() { - $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]); + $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::Argument::new(&(arg2), $crate::fmt::Display::fmt), ]); } "#]], ); @@ -229,7 +229,7 @@ macro_rules! format_args { } fn main() { - $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]); + $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(a::()), $crate::fmt::Display::fmt), $crate::fmt::Argument::new(&(b), $crate::fmt::Display::fmt), ]); } "#]], ); @@ -260,7 +260,7 @@ macro_rules! format_args { fn main() { let _ = /* parse error: expected field name or number */ -$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]); +$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(a.), $crate::fmt::Display::fmt), ]); } "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 44510f2b7ff..a9c5e1488aa 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -241,8 +241,8 @@ fn format_args_expand( // We expand `format_args!("", a1, a2)` to // ``` // $crate::fmt::Arguments::new_v1(&[], &[ - // $crate::fmt::ArgumentV1::new(&arg1,$crate::fmt::Display::fmt), - // $crate::fmt::ArgumentV1::new(&arg2,$crate::fmt::Display::fmt), + // $crate::fmt::Argument::new(&arg1,$crate::fmt::Display::fmt), + // $crate::fmt::Argument::new(&arg2,$crate::fmt::Display::fmt), // ]) // ```, // which is still not really correct, but close enough for now @@ -267,7 +267,7 @@ fn format_args_expand( } let _format_string = args.remove(0); let arg_tts = args.into_iter().flat_map(|arg| { - quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), } + quote! { #DOLLAR_CRATE::fmt::Argument::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), } }.token_trees); let expanded = quote! { #DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts]) From 0a289777402157caafcd868078814e07c0b71e5b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 24 Apr 2023 14:01:19 +0200 Subject: [PATCH 02/12] Restructure std::fmt::rt a bit. This moves more of the internal/lang items into the private rt module. --- compiler/rustc_ast_lowering/src/format.rs | 2 +- library/core/src/fmt/mod.rs | 318 ++++++---------------- library/core/src/fmt/rt.rs | 154 ++++++++++- 3 files changed, 237 insertions(+), 237 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index a4605879589..c081162ea14 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -327,7 +327,7 @@ fn make_format_spec<'hir>( None => sym::Unknown, }, ); - // This needs to match `Flag` in library/core/src/fmt/mod.rs. + // This needs to match `Flag` in library/core/src/fmt/rt.rs. let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) | ((sign == Some(FormatSign::Minus)) as u32) << 1 | (alternate as u32) << 2 diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 19d69e5c35e..f4f32232570 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -251,223 +251,6 @@ impl<'a> Formatter<'a> { } } -// NB. Argument is essentially an optimized partially applied formatting function, -// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. - -extern "C" { - type Opaque; -} - -/// This struct represents the generic "argument" which is taken by the Xprintf -/// family of functions. It contains a function to format the given value. At -/// compile time it is ensured that the function and the value have the correct -/// types, and then this struct is used to canonicalize arguments to one type. -#[lang = "format_argument"] -#[derive(Copy, Clone)] -#[allow(missing_debug_implementations)] -#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] -#[doc(hidden)] -pub struct Argument<'a> { - value: &'a Opaque, - formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, -} - -/// This struct represents the unsafety of constructing an `Arguments`. -/// It exists, rather than an unsafe function, in order to simplify the expansion -/// of `format_args!(..)` and reduce the scope of the `unsafe` block. -#[lang = "format_unsafe_arg"] -#[allow(missing_debug_implementations)] -#[doc(hidden)] -#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] -pub struct UnsafeArg { - _private: (), -} - -impl UnsafeArg { - /// See documentation where `UnsafeArg` is required to know when it is safe to - /// create and use `UnsafeArg`. - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - #[inline(always)] - pub unsafe fn new() -> Self { - Self { _private: () } - } -} - -// This guarantees a single stable value for the function pointer associated with -// indices/counts in the formatting infrastructure. -// -// Note that a function defined as such would not be correct as functions are -// always tagged unnamed_addr with the current lowering to LLVM IR, so their -// address is not considered important to LLVM and as such the as_usize cast -// could have been miscompiled. In practice, we never call as_usize on non-usize -// containing data (as a matter of static generation of the formatting -// arguments), so this is merely an additional check. -// -// We primarily want to ensure that the function pointer at `USIZE_MARKER` has -// an address corresponding *only* to functions that also take `&usize` as their -// first argument. The read_volatile here ensures that we can safely ready out a -// usize from the passed reference and that this address does not point at a -// non-usize taking function. -#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] -static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| { - // SAFETY: ptr is a reference - let _v: usize = unsafe { crate::ptr::read_volatile(ptr) }; - loop {} -}; - -macro_rules! arg_new { - ($f: ident, $t: ident) => { - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - #[inline] - pub fn $f<'b, T: $t>(x: &'b T) -> Argument<'_> { - Self::new(x, $t::fmt) - } - }; -} - -#[rustc_diagnostic_item = "ArgumentMethods"] -impl<'a> Argument<'a> { - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - #[inline] - pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { - // SAFETY: `mem::transmute(x)` is safe because - // 1. `&'b T` keeps the lifetime it originated with `'b` - // (so as to not have an unbounded lifetime) - // 2. `&'b T` and `&'b Opaque` have the same memory layout - // (when `T` is `Sized`, as it is here) - // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result` - // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI - // (as long as `T` is `Sized`) - unsafe { Argument { formatter: mem::transmute(f), value: mem::transmute(x) } } - } - - arg_new!(new_display, Display); - arg_new!(new_debug, Debug); - arg_new!(new_octal, Octal); - arg_new!(new_lower_hex, LowerHex); - arg_new!(new_upper_hex, UpperHex); - arg_new!(new_pointer, Pointer); - arg_new!(new_binary, Binary); - arg_new!(new_lower_exp, LowerExp); - arg_new!(new_upper_exp, UpperExp); - - #[doc(hidden)] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn from_usize(x: &usize) -> Argument<'_> { - Argument::new(x, USIZE_MARKER) - } - - fn as_usize(&self) -> Option { - // We are type punning a bit here: USIZE_MARKER only takes an &usize but - // formatter takes an &Opaque. Rust understandably doesn't think we should compare - // the function pointers if they don't have the same signature, so we cast to - // usizes to tell it that we just want to compare addresses. - if self.formatter as usize == USIZE_MARKER as usize { - // SAFETY: The `formatter` field is only set to USIZE_MARKER if - // the value is a usize, so this is safe - Some(unsafe { *(self.value as *const _ as *const usize) }) - } else { - None - } - } -} - -// flags available in the v1 format of format_args -#[derive(Copy, Clone)] -enum Flag { - SignPlus, - SignMinus, - Alternate, - SignAwareZeroPad, - DebugLowerHex, - DebugUpperHex, -} - -impl<'a> Arguments<'a> { - #[doc(hidden)] - #[inline] - #[unstable(feature = "fmt_internals", issue = "none")] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const fn new_const(pieces: &'a [&'static str]) -> Self { - if pieces.len() > 1 { - panic!("invalid args"); - } - Arguments { pieces, fmt: None, args: &[] } - } - - /// When using the format_args!() macro, this function is used to generate the - /// Arguments structure. - #[cfg(not(bootstrap))] - #[doc(hidden)] - #[inline] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { - if pieces.len() < args.len() || pieces.len() > args.len() + 1 { - panic!("invalid args"); - } - Arguments { pieces, fmt: None, args } - } - - #[cfg(bootstrap)] - #[doc(hidden)] - #[inline] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { - if pieces.len() < args.len() || pieces.len() > args.len() + 1 { - panic!("invalid args"); - } - Arguments { pieces, fmt: None, args } - } - - /// This function is used to specify nonstandard formatting parameters. - /// - /// An `UnsafeArg` is required because the following invariants must be held - /// in order for this function to be safe: - /// 1. The `pieces` slice must be at least as long as `fmt`. - /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. - /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. - #[doc(hidden)] - #[inline] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [Argument<'a>], - fmt: &'a [rt::Placeholder], - _unsafe_arg: UnsafeArg, - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } - } - - /// Estimates the length of the formatted text. - /// - /// This is intended to be used for setting initial `String` capacity - /// when using `format!`. Note: this is neither the lower nor upper bound. - #[doc(hidden)] - #[inline] - #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn estimated_capacity(&self) -> usize { - let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum(); - - if self.args.is_empty() { - pieces_length - } else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 { - // If the format string starts with an argument, - // don't preallocate anything, unless length - // of pieces is significant. - 0 - } else { - // There are some arguments, so any additional push - // will reallocate the string. To avoid that, - // we're "pre-doubling" the capacity here. - pieces_length.checked_mul(2).unwrap_or(0) - } - } -} - /// This structure represents a safely precompiled version of a format string /// and its arguments. This cannot be generated at runtime because it cannot /// safely be done, so no constructors are given and the fields are private @@ -502,7 +285,82 @@ pub struct Arguments<'a> { // Dynamic arguments for interpolation, to be interleaved with string // pieces. (Every argument is preceded by a string piece.) - args: &'a [Argument<'a>], + args: &'a [rt::Argument<'a>], +} + +/// Used by the format_args!() macro to create a fmt::Arguments object. +#[doc(hidden)] +#[unstable(feature = "fmt_internals", issue = "none")] +impl<'a> Arguments<'a> { + #[inline] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + pub const fn new_const(pieces: &'a [&'static str]) -> Self { + if pieces.len() > 1 { + panic!("invalid args"); + } + Arguments { pieces, fmt: None, args: &[] } + } + + /// When using the format_args!() macro, this function is used to generate the + /// Arguments structure. + #[cfg(not(bootstrap))] + #[inline] + pub fn new_v1(pieces: &'a [&'static str], args: &'a [rt::Argument<'a>]) -> Arguments<'a> { + if pieces.len() < args.len() || pieces.len() > args.len() + 1 { + panic!("invalid args"); + } + Arguments { pieces, fmt: None, args } + } + + #[cfg(bootstrap)] + #[inline] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + pub const fn new_v1(pieces: &'a [&'static str], args: &'a [rt::Argument<'a>]) -> Arguments<'a> { + if pieces.len() < args.len() || pieces.len() > args.len() + 1 { + panic!("invalid args"); + } + Arguments { pieces, fmt: None, args } + } + + /// This function is used to specify nonstandard formatting parameters. + /// + /// An `rt::UnsafeArg` is required because the following invariants must be held + /// in order for this function to be safe: + /// 1. The `pieces` slice must be at least as long as `fmt`. + /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. + /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. + #[inline] + pub fn new_v1_formatted( + pieces: &'a [&'static str], + args: &'a [rt::Argument<'a>], + fmt: &'a [rt::Placeholder], + _unsafe_arg: rt::UnsafeArg, + ) -> Arguments<'a> { + Arguments { pieces, fmt: Some(fmt), args } + } + + /// Estimates the length of the formatted text. + /// + /// This is intended to be used for setting initial `String` capacity + /// when using `format!`. Note: this is neither the lower nor upper bound. + #[inline] + pub fn estimated_capacity(&self) -> usize { + let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum(); + + if self.args.is_empty() { + pieces_length + } else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 { + // If the format string starts with an argument, + // don't preallocate anything, unless length + // of pieces is significant. + 0 + } else { + // There are some arguments, so any additional push + // will reallocate the string. To avoid that, + // we're "pre-doubling" the capacity here. + pieces_length.checked_mul(2).unwrap_or(0) + } + } } impl<'a> Arguments<'a> { @@ -1244,7 +1102,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { if !piece.is_empty() { formatter.buf.write_str(*piece)?; } - (arg.formatter)(arg.value, &mut formatter)?; + arg.fmt(&mut formatter)?; idx += 1; } } @@ -1274,7 +1132,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { Ok(()) } -unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[Argument<'_>]) -> Result { +unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argument<'_>]) -> Result { fmt.fill = arg.fill; fmt.align = arg.align; fmt.flags = arg.flags; @@ -1292,10 +1150,10 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[Argument<' let value = unsafe { args.get_unchecked(arg.position) }; // Then actually do some printing - (value.formatter)(value.value, fmt) + value.fmt(fmt) } -unsafe fn getcount(args: &[Argument<'_>], cnt: &rt::Count) -> Option { +unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { match *cnt { rt::Count::Is(n) => Some(n), rt::Count::Implied => None, @@ -1878,7 +1736,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_plus(&self) -> bool { - self.flags & (1 << Flag::SignPlus as u32) != 0 + self.flags & (1 << rt::Flag::SignPlus as u32) != 0 } /// Determines if the `-` flag was specified. @@ -1907,7 +1765,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_minus(&self) -> bool { - self.flags & (1 << Flag::SignMinus as u32) != 0 + self.flags & (1 << rt::Flag::SignMinus as u32) != 0 } /// Determines if the `#` flag was specified. @@ -1935,7 +1793,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn alternate(&self) -> bool { - self.flags & (1 << Flag::Alternate as u32) != 0 + self.flags & (1 << rt::Flag::Alternate as u32) != 0 } /// Determines if the `0` flag was specified. @@ -1961,17 +1819,17 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn sign_aware_zero_pad(&self) -> bool { - self.flags & (1 << Flag::SignAwareZeroPad as u32) != 0 + self.flags & (1 << rt::Flag::SignAwareZeroPad as u32) != 0 } // FIXME: Decide what public API we want for these two flags. // https://github.com/rust-lang/rust/issues/48584 fn debug_lower_hex(&self) -> bool { - self.flags & (1 << Flag::DebugLowerHex as u32) != 0 + self.flags & (1 << rt::Flag::DebugLowerHex as u32) != 0 } fn debug_upper_hex(&self) -> bool { - self.flags & (1 << Flag::DebugUpperHex as u32) != 0 + self.flags & (1 << rt::Flag::DebugUpperHex as u32) != 0 } /// Creates a [`DebugStruct`] builder designed to assist with creation of @@ -2531,13 +2389,13 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul // or not to zero extend, and then unconditionally set it to get the // prefix. if f.alternate() { - f.flags |= 1 << (Flag::SignAwareZeroPad as u32); + f.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); if f.width.is_none() { f.width = Some((usize::BITS / 4) as usize + 2); } } - f.flags |= 1 << (Flag::Alternate as u32); + f.flags |= 1 << (rt::Flag::Alternate as u32); let ret = LowerHex::fmt(&ptr_addr, f); diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 2c1a767691b..8498f5f5a7c 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -3,6 +3,8 @@ //! These are the lang items used by format_args!(). +use super::*; + #[lang = "format_placeholder"] #[derive(Copy, Clone)] pub struct Placeholder { @@ -28,21 +30,17 @@ impl Placeholder { } } -/// Possible alignments that can be requested as part of a formatting directive. #[lang = "format_alignment"] #[derive(Copy, Clone, PartialEq, Eq)] pub enum Alignment { - /// Indication that contents should be left-aligned. Left, - /// Indication that contents should be right-aligned. Right, - /// Indication that contents should be center-aligned. Center, - /// No alignment was requested. Unknown, } -/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. +/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) +/// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. #[lang = "format_count"] #[derive(Copy, Clone)] pub enum Count { @@ -53,3 +51,147 @@ pub enum Count { /// Not specified Implied, } + +// This needs to match the order of flags in compiler/rustc_ast_lowering/src/format.rs. +#[derive(Copy, Clone)] +pub enum Flag { + SignPlus, + SignMinus, + Alternate, + SignAwareZeroPad, + DebugLowerHex, + DebugUpperHex, +} + +/// This struct represents the generic "argument" which is taken by format_args!(). +/// It contains a function to format the given value. At compile time it is ensured that the +/// function and the value have the correct types, and then this struct is used to canonicalize +/// arguments to one type. +/// +/// Argument is essentially an optimized partially applied formatting function, +/// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. +#[lang = "format_argument"] +#[derive(Copy, Clone)] +pub struct Argument<'a> { + value: &'a Opaque, + formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, +} + +#[rustc_diagnostic_item = "ArgumentMethods"] +impl<'a> Argument<'a> { + #[inline(always)] + fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> { + // SAFETY: `mem::transmute(x)` is safe because + // 1. `&'b T` keeps the lifetime it originated with `'b` + // (so as to not have an unbounded lifetime) + // 2. `&'b T` and `&'b Opaque` have the same memory layout + // (when `T` is `Sized`, as it is here) + // `mem::transmute(f)` is safe since `fn(&T, &mut Formatter<'_>) -> Result` + // and `fn(&Opaque, &mut Formatter<'_>) -> Result` have the same ABI + // (as long as `T` is `Sized`) + unsafe { Argument { formatter: mem::transmute(f), value: mem::transmute(x) } } + } + + #[inline(always)] + pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> { + Self::new(x, Display::fmt) + } + #[inline(always)] + pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> { + Self::new(x, Debug::fmt) + } + #[inline(always)] + pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_> { + Self::new(x, Octal::fmt) + } + #[inline(always)] + pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_> { + Self::new(x, LowerHex::fmt) + } + #[inline(always)] + pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_> { + Self::new(x, UpperHex::fmt) + } + #[inline(always)] + pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_> { + Self::new(x, Pointer::fmt) + } + #[inline(always)] + pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_> { + Self::new(x, Binary::fmt) + } + #[inline(always)] + pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_> { + Self::new(x, LowerExp::fmt) + } + #[inline(always)] + pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_> { + Self::new(x, UpperExp::fmt) + } + #[inline(always)] + pub fn from_usize(x: &usize) -> Argument<'_> { + Self::new(x, USIZE_MARKER) + } + + #[inline(always)] + pub(super) fn fmt(&self, f: &mut Formatter<'_>) -> Result { + (self.formatter)(self.value, f) + } + + #[inline(always)] + pub(super) fn as_usize(&self) -> Option { + // We are type punning a bit here: USIZE_MARKER only takes an &usize but + // formatter takes an &Opaque. Rust understandably doesn't think we should compare + // the function pointers if they don't have the same signature, so we cast to + // usizes to tell it that we just want to compare addresses. + if self.formatter as usize == USIZE_MARKER as usize { + // SAFETY: The `formatter` field is only set to USIZE_MARKER if + // the value is a usize, so this is safe + Some(unsafe { *(self.value as *const _ as *const usize) }) + } else { + None + } + } +} + +/// This struct represents the unsafety of constructing an `Arguments`. +/// It exists, rather than an unsafe function, in order to simplify the expansion +/// of `format_args!(..)` and reduce the scope of the `unsafe` block. +#[lang = "format_unsafe_arg"] +pub struct UnsafeArg { + _private: (), +} + +impl UnsafeArg { + /// See documentation where `UnsafeArg` is required to know when it is safe to + /// create and use `UnsafeArg`. + #[inline(always)] + pub unsafe fn new() -> Self { + Self { _private: () } + } +} + +extern "C" { + type Opaque; +} + +// This guarantees a single stable value for the function pointer associated with +// indices/counts in the formatting infrastructure. +// +// Note that a function defined as such would not be correct as functions are +// always tagged unnamed_addr with the current lowering to LLVM IR, so their +// address is not considered important to LLVM and as such the as_usize cast +// could have been miscompiled. In practice, we never call as_usize on non-usize +// containing data (as a matter of static generation of the formatting +// arguments), so this is merely an additional check. +// +// We primarily want to ensure that the function pointer at `USIZE_MARKER` has +// an address corresponding *only* to functions that also take `&usize` as their +// first argument. The read_volatile here ensures that we can safely ready out a +// usize from the passed reference and that this address does not point at a +// non-usize taking function. +static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| { + // SAFETY: ptr is a reference + let _v: usize = unsafe { crate::ptr::read_volatile(ptr) }; + loop {} +}; From 9cc5949f9f386fcb8e4492cc6b112a11b342e1dd Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 20 Apr 2023 20:18:22 +0200 Subject: [PATCH 03/12] Update tests. --- ...mes.foo.ScalarReplacementOfAggregates.diff | 24 ++++++++-------- tests/ui/fmt/ifmt-bad-arg.stderr | 4 +-- tests/ui/fmt/ifmt-unimpl.stderr | 6 ++-- tests/ui/fmt/send-sync.stderr | 28 +++++++++---------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index 579587a430b..9bda5f575c9 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -15,14 +15,14 @@ let mut _13: &[&str; 3]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28 let _14: &[&str; 3]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28 let _15: [&str; 3]; // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28 - let mut _16: &[core::fmt::ArgumentV1<'_>]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _17: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _18: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _19: [core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _20: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23 + let mut _16: &[core::fmt::rt::Argument<'_>]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _17: &[core::fmt::rt::Argument<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _18: &[core::fmt::rt::Argument<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _19: [core::fmt::rt::Argument<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _20: core::fmt::rt::Argument<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23 let mut _21: &std::boxed::Box; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23 let _22: &std::boxed::Box; // in scope 0 at $DIR/lifetimes.rs:+10:20: +10:23 - let mut _23: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27 + let mut _23: core::fmt::rt::Argument<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27 let mut _24: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27 let _25: &u32; // in scope 0 at $DIR/lifetimes.rs:+10:24: +10:27 let mut _27: bool; // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2 @@ -113,11 +113,11 @@ StorageLive(_22); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 _22 = &_8; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 _21 = &(*_22); // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 - _20 = core::fmt::ArgumentV1::<'_>::new_display::>(move _21) -> [return: bb3, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 + _20 = core::fmt::rt::Argument::<'_>::new_display::>(move _21) -> [return: bb3, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:20: +10:23 // mir::Constant // + span: $DIR/lifetimes.rs:27:20: 27:23 // + user_ty: UserType(4) - // + literal: Const { ty: for<'b> fn(&'b Box) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::>}, val: Value() } + // + literal: Const { ty: for<'b> fn(&'b Box) -> core::fmt::rt::Argument<'b> {core::fmt::rt::Argument::<'_>::new_display::>}, val: Value() } } bb3: { @@ -127,11 +127,11 @@ StorageLive(_25); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 _25 = &_6; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 _24 = &(*_25); // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 - _23 = core::fmt::ArgumentV1::<'_>::new_display::(move _24) -> [return: bb4, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 + _23 = core::fmt::rt::Argument::<'_>::new_display::(move _24) -> [return: bb4, unwind unreachable]; // scope 4 at $DIR/lifetimes.rs:+10:24: +10:27 // mir::Constant // + span: $DIR/lifetimes.rs:27:24: 27:27 // + user_ty: UserType(5) - // + literal: Const { ty: for<'b> fn(&'b u32) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::}, val: Value() } + // + literal: Const { ty: for<'b> fn(&'b u32) -> core::fmt::rt::Argument<'b> {core::fmt::rt::Argument::<'_>::new_display::}, val: Value() } } bb4: { @@ -141,13 +141,13 @@ StorageDead(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _18 = &_19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _17 = &(*_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _16 = move _17 as &[core::fmt::ArgumentV1<'_>] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _16 = move _17 as &[core::fmt::rt::Argument<'_>] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageDead(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _11 = Arguments::<'_>::new_v1(move _12, move _16) -> [return: bb5, unwind unreachable]; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + user_ty: UserType(3) - // + literal: Const { ty: fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1}, val: Value() } + // + literal: Const { ty: fn(&[&'static str], &[core::fmt::rt::Argument<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1}, val: Value() } } bb5: { diff --git a/tests/ui/fmt/ifmt-bad-arg.stderr b/tests/ui/fmt/ifmt-bad-arg.stderr index bf18fb315c9..ed008c454a3 100644 --- a/tests/ui/fmt/ifmt-bad-arg.stderr +++ b/tests/ui/fmt/ifmt-bad-arg.stderr @@ -307,7 +307,7 @@ LL | println!("{} {:.*} {}", 1, 3.2, 4); = note: expected reference `&usize` found reference `&{float}` note: associated function defined here - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types @@ -321,7 +321,7 @@ LL | println!("{} {:07$.*} {}", 1, 3.2, 4); = note: expected reference `&usize` found reference `&{float}` note: associated function defined here - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 38 previous errors diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index dc2dee3f341..cc316e55f5c 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -17,9 +17,9 @@ LL | format!("{:X}", "3"); NonZeroIsize and 21 others = note: required for `&str` to implement `UpperHex` -note: required by a bound in `core::fmt::ArgumentV1::<'a>::new_upper_hex` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `arg_new` (in Nightly builds, run with -Z macro-backtrace for more info) +note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex` + --> $SRC_DIR/core/src/fmt/rt.rs:LL:COL + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/ui/fmt/send-sync.stderr b/tests/ui/fmt/send-sync.stderr index d43f4f0d957..b517a342e63 100644 --- a/tests/ui/fmt/send-sync.stderr +++ b/tests/ui/fmt/send-sync.stderr @@ -1,16 +1,16 @@ -error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely +error[E0277]: `core::fmt::rt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:8:10 | LL | send(format_args!("{:?}", c)); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::Opaque` cannot be shared between threads safely + | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::rt::Opaque` cannot be shared between threads safely | | | required by a bound introduced by this call | - = help: within `[core::fmt::ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` - = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `ArgumentV1<'_>` - = note: required because it appears within the type `[ArgumentV1<'_>]` - = note: required for `&[core::fmt::ArgumentV1<'_>]` to implement `Send` + = help: within `[core::fmt::rt::Argument<'_>]`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque` + = note: required because it appears within the type `&core::fmt::rt::Opaque` + = note: required because it appears within the type `Argument<'_>` + = note: required because it appears within the type `[Argument<'_>]` + = note: required for `&[core::fmt::rt::Argument<'_>]` to implement `Send` = note: required because it appears within the type `Arguments<'_>` note: required by a bound in `send` --> $DIR/send-sync.rs:1:12 @@ -18,19 +18,19 @@ note: required by a bound in `send` LL | fn send(_: T) {} | ^^^^ required by this bound in `send` -error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely +error[E0277]: `core::fmt::rt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:9:10 | LL | sync(format_args!("{:?}", c)); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::Opaque` cannot be shared between threads safely + | ---- ^^^^^^^^^^^^^^^^^^^^^^^ `core::fmt::rt::Opaque` cannot be shared between threads safely | | | required by a bound introduced by this call | - = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::Opaque` - = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `ArgumentV1<'_>` - = note: required because it appears within the type `[ArgumentV1<'_>]` - = note: required because it appears within the type `&[ArgumentV1<'_>]` + = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::rt::Opaque` + = note: required because it appears within the type `&core::fmt::rt::Opaque` + = note: required because it appears within the type `Argument<'_>` + = note: required because it appears within the type `[Argument<'_>]` + = note: required because it appears within the type `&[Argument<'_>]` = note: required because it appears within the type `Arguments<'_>` note: required by a bound in `sync` --> $DIR/send-sync.rs:2:12 From 7bae143cfbcf590bd4564161556824b539cad0d7 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 24 Apr 2023 17:22:57 +0200 Subject: [PATCH 04/12] Update miri test. --- .../miri/tests/fail/panic/double_panic.stderr | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 6bf13f21601..f04dfab36ca 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -12,57 +12,59 @@ stack backtrace: at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 4: ::fmt at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - 5: std::fmt::write + 5: core::fmt::rt::Argument::fmt + at RUSTLIB/core/src/fmt/rt.rs:LL:CC + 6: std::fmt::write at RUSTLIB/core/src/fmt/mod.rs:LL:CC - 6: ::write_fmt + 7: ::write_fmt at RUSTLIB/std/src/io/mod.rs:LL:CC - 7: std::sys_common::backtrace::_print + 8: std::sys_common::backtrace::_print at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - 8: std::sys_common::backtrace::print + 9: std::sys_common::backtrace::print at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - 9: std::panicking::default_hook::{closure#1} + 10: std::panicking::default_hook::{closure#1} at RUSTLIB/std/src/panicking.rs:LL:CC - 10: std::panicking::default_hook + 11: std::panicking::default_hook at RUSTLIB/std/src/panicking.rs:LL:CC - 11: std::panicking::rust_panic_with_hook + 12: std::panicking::rust_panic_with_hook at RUSTLIB/std/src/panicking.rs:LL:CC - 12: std::rt::begin_panic::{closure#0} + 13: std::rt::begin_panic::{closure#0} at RUSTLIB/std/src/panicking.rs:LL:CC - 13: std::sys_common::backtrace::__rust_end_short_backtrace + 14: std::sys_common::backtrace::__rust_end_short_backtrace at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - 14: std::rt::begin_panic + 15: std::rt::begin_panic at RUSTLIB/std/src/panicking.rs:LL:CC - 15: ::drop + 16: ::drop at $DIR/double_panic.rs:LL:CC - 16: std::ptr::drop_in_place - shim(Some(Foo)) + 17: std::ptr::drop_in_place - shim(Some(Foo)) at RUSTLIB/core/src/ptr/mod.rs:LL:CC - 17: main + 18: main at $DIR/double_panic.rs:LL:CC - 18: >::call_once - shim(fn()) + 19: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC - 19: std::sys_common::backtrace::__rust_begin_short_backtrace + 20: std::sys_common::backtrace::__rust_begin_short_backtrace at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - 20: std::rt::lang_start::{closure#0} + 21: std::rt::lang_start::{closure#0} at RUSTLIB/std/src/rt.rs:LL:CC - 21: std::ops::function::impls::call_once + 22: std::ops::function::impls::call_once at RUSTLIB/core/src/ops/function.rs:LL:CC - 22: std::panicking::r#try::do_call + 23: std::panicking::r#try::do_call at RUSTLIB/std/src/panicking.rs:LL:CC - 23: std::panicking::r#try + 24: std::panicking::r#try at RUSTLIB/std/src/panicking.rs:LL:CC - 24: std::panic::catch_unwind + 25: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC - 25: std::rt::lang_start_internal::{closure#2} + 26: std::rt::lang_start_internal::{closure#2} at RUSTLIB/std/src/rt.rs:LL:CC - 26: std::panicking::r#try::do_call + 27: std::panicking::r#try::do_call at RUSTLIB/std/src/panicking.rs:LL:CC - 27: std::panicking::r#try + 28: std::panicking::r#try at RUSTLIB/std/src/panicking.rs:LL:CC - 28: std::panic::catch_unwind + 29: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC - 29: std::rt::lang_start_internal + 30: std::rt::lang_start_internal at RUSTLIB/std/src/rt.rs:LL:CC - 30: std::rt::lang_start + 31: std::rt::lang_start at RUSTLIB/std/src/rt.rs:LL:CC thread panicked while panicking. aborting. error: abnormal termination: the program aborted execution From 1ce9d7254e3e890a4b60846072e5731231f7e030 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 27 Apr 2023 01:53:06 +0100 Subject: [PATCH 05/12] Migrate trivially translatable `rustc_parse` diagnostics --- compiler/rustc_ast/src/ast.rs | 4 +- compiler/rustc_parse/messages.ftl | 72 ++++++ compiler/rustc_parse/src/errors.rs | 224 ++++++++++++++++++ compiler/rustc_parse/src/lib.rs | 17 +- compiler/rustc_parse/src/parser/expr.rs | 12 +- compiler/rustc_parse/src/parser/item.rs | 119 +++------- compiler/rustc_parse/src/parser/mod.rs | 15 +- compiler/rustc_parse/src/parser/pat.rs | 21 +- compiler/rustc_parse/src/parser/path.rs | 21 +- compiler/rustc_parse/src/parser/ty.rs | 30 +-- compiler/rustc_parse/src/validate_attr.rs | 27 ++- tests/ui/macros/missing-bang-in-decl.stderr | 14 +- tests/ui/parser/item-kw-case-mismatch.fixed | 28 +-- tests/ui/parser/item-kw-case-mismatch.rs | 28 +-- tests/ui/parser/item-kw-case-mismatch.stderr | 28 +-- .../ui/parser/recover-unticked-labels.stderr | 8 +- tests/ui/parser/use-colon-as-mod-sep.stderr | 6 + 17 files changed, 443 insertions(+), 231 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1e4d3ba47f4..3ed342ce48b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2976,7 +2976,7 @@ pub enum ItemKind { } impl ItemKind { - pub fn article(&self) -> &str { + pub fn article(&self) -> &'static str { use ItemKind::*; match self { Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..) @@ -2985,7 +2985,7 @@ impl ItemKind { } } - pub fn descr(&self) -> &str { + pub fn descr(&self) -> &'static str { match self { ItemKind::ExternCrate(..) => "extern crate", ItemKind::Use(..) => "`use` import", diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index d45fa90a11b..9c4fac84fc2 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -772,3 +772,75 @@ parse_const_bounds_missing_tilde = const bounds must start with `~` .suggestion = add `~` parse_underscore_literal_suffix = underscore literal suffix is not allowed + +parse_expect_label_found_ident = expected a label, found an identifier + .suggestion = labels start with a tick + +parse_inappropriate_default = {$article} {$descr} cannot be `default` + .label = `default` because of this + .note = only associated `fn`, `const`, and `type` items can be `default` + +parse_recover_import_as_use = expected item, found {$token_name} + .suggestion = items are imported using the `use` keyword + +parse_single_colon_import_path = expected `::`, found `:` + .suggestion = use double colon + .note = import paths are delimited using `::` + +parse_bad_item_kind = {$descr} is not supported in {$ctx} + .help = consider moving the {$descr} out to a nearby module scope + +parse_single_colon_struct_type = found single colon in a struct field type path + .suggestion = write a path separator here + +parse_equals_struct_default = default values on `struct` fields aren't supported + .suggestion = remove this unsupported default value + +parse_macro_rules_missing_bang = expected `!` after `macro_rules` + .suggestion = add a `!` + +parse_macro_name_remove_bang = macro names aren't followed by a `!` + .suggestion = remove the `!` + +parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}` + .suggestion = try exporting the macro + +parse_macro_invocation_visibility = can't qualify macro invocation with `pub` + .suggestion = remove the visibility + .help = try adjusting the macro to put `{$vis}` inside the invocation + +parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}` + .suggestion = consider creating a new `{$kw_str}` definition instead of nesting + +parse_function_body_equals_expr = function body cannot be `= expression;` + .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` + +parse_box_not_pat = expected pattern, found {$descr} + .note = `box` is a reserved keyword + .suggestion = escape `box` to use it as an identifier + +parse_unmatched_angle = unmatched angle {$plural -> + [true] brackets + *[false] bracket + } + .suggestion = remove extra angle {$plural -> + [true] brackets + *[false] bracket + } + +parse_missing_plus_in_bounds = expected `+` between lifetime and {$sym} + .suggestion = add `+` + +parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds + .suggestion = remove the parentheses + +parse_kw_bad_case = keyword `{$kw}` is written in the wrong case + .suggestion = write it in the correct case + +parse_meta_bad_delim = wrong meta list delimiters +parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters +parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)` + +parse_malformed_cfg_attr = malformed `cfg_attr` attribute input + .suggestion = missing condition and attribute + .note = for more information, visit diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index b0e1189851a..f286707a9c0 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2421,3 +2421,227 @@ pub(crate) struct UnderscoreLiteralSuffix { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_expect_label_found_ident)] +pub(crate) struct ExpectedLabelFoundIdent { + #[primary_span] + pub span: Span, + #[suggestion(code = "'", applicability = "machine-applicable", style = "short")] + pub start: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_inappropriate_default)] +#[note] +pub(crate) struct InappropriateDefault { + #[primary_span] + #[label] + pub span: Span, + pub article: &'static str, + pub descr: &'static str, +} + +#[derive(Diagnostic)] +#[diag(parse_recover_import_as_use)] +pub(crate) struct RecoverImportAsUse { + #[primary_span] + #[suggestion(code = "use", applicability = "machine-applicable", style = "short")] + pub span: Span, + pub token_name: String, +} + +#[derive(Diagnostic)] +#[diag(parse_single_colon_import_path)] +#[note] +pub(crate) struct SingleColonImportPath { + #[primary_span] + #[suggestion(code = "::", applicability = "machine-applicable", style = "short")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_bad_item_kind)] +#[help] +pub(crate) struct BadItemKind { + #[primary_span] + pub span: Span, + pub descr: &'static str, + pub ctx: &'static str, +} + +#[derive(Diagnostic)] +#[diag(parse_single_colon_struct_type)] +pub(crate) struct SingleColonStructType { + #[primary_span] + #[suggestion(code = "::", applicability = "maybe-incorrect", style = "verbose")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_equals_struct_default)] +pub(crate) struct EqualsStructDefault { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_macro_rules_missing_bang)] +pub(crate) struct MacroRulesMissingBang { + #[primary_span] + pub span: Span, + #[suggestion(code = "!", applicability = "machine-applicable", style = "verbose")] + pub hi: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_macro_name_remove_bang)] +pub(crate) struct MacroNameRemoveBang { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_macro_rules_visibility)] +pub(crate) struct MacroRulesVisibility<'a> { + #[primary_span] + #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect")] + pub span: Span, + pub vis: &'a str, +} + +#[derive(Diagnostic)] +#[diag(parse_macro_invocation_visibility)] +#[help] +pub(crate) struct MacroInvocationVisibility<'a> { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, + pub vis: &'a str, +} + +#[derive(Diagnostic)] +#[diag(parse_nested_adt)] +pub(crate) struct NestedAdt<'a> { + #[primary_span] + pub span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub item: Span, + pub keyword: &'a str, + pub kw_str: Cow<'a, str>, +} + +#[derive(Diagnostic)] +#[diag(parse_function_body_equals_expr)] +pub(crate) struct FunctionBodyEqualsExpr { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: FunctionBodyEqualsExprSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] +pub(crate) struct FunctionBodyEqualsExprSugg { + #[suggestion_part(code = "{{")] + pub eq: Span, + #[suggestion_part(code = " }}")] + pub semi: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_box_not_pat)] +pub(crate) struct BoxNotPat { + #[primary_span] + pub span: Span, + #[note] + pub kw: Span, + #[suggestion(code = "r#", applicability = "maybe-incorrect", style = "verbose")] + pub lo: Span, + pub descr: String, +} + +#[derive(Diagnostic)] +#[diag(parse_unmatched_angle)] +pub(crate) struct UnmatchedAngle { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub span: Span, + pub plural: bool, +} + +#[derive(Diagnostic)] +#[diag(parse_missing_plus_in_bounds)] +pub(crate) struct MissingPlusBounds { + #[primary_span] + pub span: Span, + #[suggestion(code = " +", applicability = "maybe-incorrect", style = "verbose")] + pub hi: Span, + pub sym: Symbol, +} + +#[derive(Diagnostic)] +#[diag(parse_incorrect_braces_trait_bounds)] +pub(crate) struct IncorrectBracesTraitBounds { + #[primary_span] + pub span: Vec, + #[subdiagnostic] + pub sugg: IncorrectBracesTraitBoundsSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] +pub(crate) struct IncorrectBracesTraitBoundsSugg { + #[suggestion_part(code = " ")] + pub l: Span, + #[suggestion_part(code = "")] + pub r: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_kw_bad_case)] +pub(crate) struct KwBadCase<'a> { + #[primary_span] + #[suggestion(code = "{kw}", applicability = "machine-applicable")] + pub span: Span, + pub kw: &'a str, +} + +#[derive(Diagnostic)] +#[diag(parse_meta_bad_delim)] +pub(crate) struct MetaBadDelim { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: MetaBadDelimSugg, +} + +#[derive(Diagnostic)] +#[diag(parse_cfg_attr_bad_delim)] +pub(crate) struct CfgAttrBadDelim { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: MetaBadDelimSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_meta_bad_delim_suggestion, applicability = "machine-applicable")] +pub(crate) struct MetaBadDelimSugg { + #[suggestion_part(code = "(")] + pub open: Span, + #[suggestion_part(code = ")")] + pub close: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_malformed_cfg_attr)] +#[note] +pub(crate) struct MalformedCfgAttr { + #[primary_span] + #[suggestion(code = "{sugg}")] + pub span: Span, + pub sugg: &'static str, +} diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 507f6e4182e..61a1cdeb540 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -18,7 +18,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrItem, Attribute, MetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult}; +use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_session::parse::ParseSess; @@ -243,8 +243,7 @@ pub fn parse_cfg_attr( ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => { - let msg = "wrong `cfg_attr` delimiters"; - crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg); + crate::validate_attr::check_cfg_attr_bad_delim(parse_sess, dspan, delim); match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { Ok(r) => return Some(r), Err(mut e) => { @@ -265,15 +264,5 @@ const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ #the-cfg_attr-attribute>"; fn error_malformed_cfg_attr_missing(span: Span, parse_sess: &ParseSess) { - parse_sess - .span_diagnostic - .struct_span_err(span, "malformed `cfg_attr` attribute input") - .span_suggestion( - span, - "missing condition and attribute", - CFG_ATTR_GRAMMAR_HELP, - Applicability::HasPlaceholders, - ) - .note(CFG_ATTR_NOTE_REF) - .emit(); + parse_sess.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP }); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 03c82fbd329..27de9bd7268 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3151,14 +3151,10 @@ impl<'a> Parser<'a> { let label = format!("'{}", ident.name); let ident = Ident { name: Symbol::intern(&label), span: ident.span }; - self.struct_span_err(ident.span, "expected a label, found an identifier") - .span_suggestion( - ident.span, - "labels start with a tick", - label, - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(errors::ExpectedLabelFoundIdent { + span: ident.span, + start: ident.span.shrink_to_lo(), + }); Label { ident } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index f5fef6ad019..9e003bfc097 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -181,11 +181,11 @@ impl<'a> Parser<'a> { /// Error in-case `default` was parsed in an in-appropriate context. fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) { if let Defaultness::Default(span) = def { - let msg = format!("{} {} cannot be `default`", kind.article(), kind.descr()); - self.struct_span_err(span, &msg) - .span_label(span, "`default` because of this") - .note("only associated `fn`, `const`, and `type` items can be `default`") - .emit(); + self.sess.emit_err(errors::InappropriateDefault { + span, + article: kind.article(), + descr: kind.descr(), + }); } } @@ -310,14 +310,7 @@ impl<'a> Parser<'a> { self.bump(); match self.parse_use_item() { Ok(u) => { - self.struct_span_err(span, format!("expected item, found {token_name}")) - .span_suggestion_short( - span, - "items are imported using the `use` keyword", - "use", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(errors::RecoverImportAsUse { span, token_name }); Ok(Some(u)) } Err(e) => { @@ -963,15 +956,8 @@ impl<'a> Parser<'a> { } else { // Recover from using a colon as path separator. while self.eat_noexpect(&token::Colon) { - self.struct_span_err(self.prev_token.span, "expected `::`, found `:`") - .span_suggestion_short( - self.prev_token.span, - "use double colon", - "::", - Applicability::MachineApplicable, - ) - .note_once("import paths are delimited using `::`") - .emit(); + self.sess + .emit_err(errors::SingleColonImportPath { span: self.prev_token.span }); // We parse the rest of the path and append it to the original prefix. self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?; @@ -1134,13 +1120,11 @@ impl<'a> Parser<'a> { )) } - fn error_bad_item_kind(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option { + fn error_bad_item_kind(&self, span: Span, kind: &ItemKind, ctx: &'static str) -> Option { // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`) let span = self.sess.source_map().guess_head_span(span); let descr = kind.descr(); - self.struct_span_err(span, &format!("{descr} is not supported in {ctx}")) - .help(&format!("consider moving the {descr} out to a nearby module scope")) - .emit(); + self.sess.emit_err(errors::BadItemKind { span, descr, ctx }); None } @@ -1713,27 +1697,13 @@ impl<'a> Parser<'a> { self.expect_field_ty_separator()?; let ty = self.parse_ty()?; if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) { - self.struct_span_err(self.token.span, "found single colon in a struct field type path") - .span_suggestion_verbose( - self.token.span, - "write a path separator here", - "::", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(errors::SingleColonStructType { span: self.token.span }); } if self.token.kind == token::Eq { self.bump(); let const_expr = self.parse_expr_anon_const()?; let sp = ty.span.shrink_to_hi().to(const_expr.value.span); - self.struct_span_err(sp, "default values on `struct` fields aren't supported") - .span_suggestion( - sp, - "remove this unsupported default value", - "", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(errors::EqualsStructDefault { span: sp }); } Ok(FieldDef { span: lo.to(self.prev_token.span), @@ -1871,14 +1841,10 @@ impl<'a> Parser<'a> { return IsMacroRulesItem::Yes { has_bang: true }; } else if self.look_ahead(1, |t| (t.is_ident())) { // macro_rules foo - self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`") - .span_suggestion( - macro_rules_span, - "add a `!`", - "macro_rules!", - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(errors::MacroRulesMissingBang { + span: macro_rules_span, + hi: macro_rules_span.shrink_to_hi(), + }); return IsMacroRulesItem::Yes { has_bang: false }; } @@ -1903,9 +1869,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Not) { // Handle macro_rules! foo! let span = self.prev_token.span; - self.struct_span_err(span, "macro names aren't followed by a `!`") - .span_suggestion(span, "remove the `!`", "", Applicability::MachineApplicable) - .emit(); + self.sess.emit_err(errors::MacroNameRemoveBang { span }); } let body = self.parse_delim_args()?; @@ -1925,25 +1889,9 @@ impl<'a> Parser<'a> { let vstr = pprust::vis_to_string(vis); let vstr = vstr.trim_end(); if macro_rules { - let msg = format!("can't qualify macro_rules invocation with `{vstr}`"); - self.struct_span_err(vis.span, &msg) - .span_suggestion( - vis.span, - "try exporting the macro", - "#[macro_export]", - Applicability::MaybeIncorrect, // speculative - ) - .emit(); + self.sess.emit_err(errors::MacroRulesVisibility { span: vis.span, vis: vstr }); } else { - self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`") - .span_suggestion( - vis.span, - "remove the visibility", - "", - Applicability::MachineApplicable, - ) - .help(&format!("try adjusting the macro to put `{vstr}` inside the invocation")) - .emit(); + self.sess.emit_err(errors::MacroInvocationVisibility { span: vis.span, vis: vstr }); } } @@ -1989,18 +1937,12 @@ impl<'a> Parser<'a> { let kw_token = self.token.clone(); let kw_str = pprust::token_to_string(&kw_token); let item = self.parse_item(ForceCollect::No)?; - - self.struct_span_err( - kw_token.span, - &format!("`{kw_str}` definition cannot be nested inside `{keyword}`"), - ) - .span_suggestion( - item.unwrap().span, - &format!("consider creating a new `{kw_str}` definition instead of nesting"), - "", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(errors::NestedAdt { + span: kw_token.span, + item: item.unwrap().span, + kw_str, + keyword: keyword.as_str(), + }); // We successfully parsed the item but we must inform the caller about nested problem. return Ok(false); } @@ -2139,13 +2081,10 @@ impl<'a> Parser<'a> { let _ = self.parse_expr()?; self.expect_semi()?; // `;` let span = eq_sp.to(self.prev_token.span); - self.struct_span_err(span, "function body cannot be `= expression;`") - .multipart_suggestion( - "surround the expression with `{` and `}` instead of `=` and `;`", - vec![(eq_sp, "{".to_string()), (self.prev_token.span, " }".to_string())], - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(errors::FunctionBodyEqualsExpr { + span, + sugg: errors::FunctionBodyEqualsExprSugg { eq: eq_sp, semi: self.prev_token.span }, + }); (AttrVec::new(), Some(self.mk_block_err(span))) } else { let expected = if req_body { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index aa57b804779..1c34e491f21 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -43,7 +43,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::errors::{ - IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, + self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, }; bitflags::bitflags! { @@ -663,15 +663,10 @@ impl<'a> Parser<'a> { if case == Case::Insensitive && let Some((ident, /* is_raw */ false)) = self.token.ident() && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { - self - .struct_span_err(ident.span, format!("keyword `{kw}` is written in a wrong case")) - .span_suggestion( - ident.span, - "write it in the correct case", - kw, - Applicability::MachineApplicable - ).emit(); - + self.sess.emit_err(errors::KwBadCase { + span: ident.span, + kw: kw.as_str() + }); self.bump(); return true; } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 2246002f5d3..f2422fe307c 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,6 +1,6 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; use crate::errors::{ - AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, + self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, @@ -908,18 +908,13 @@ impl<'a> Parser<'a> { let box_span = self.prev_token.span; if self.isnt_pattern_start() { - self.struct_span_err( - self.token.span, - format!("expected pattern, found {}", super::token_descr(&self.token)), - ) - .span_note(box_span, "`box` is a reserved keyword") - .span_suggestion_verbose( - box_span.shrink_to_lo(), - "escape `box` to use it as an identifier", - "r#", - Applicability::MaybeIncorrect, - ) - .emit(); + let descr = super::token_descr(&self.token); + self.sess.emit_err(errors::BoxNotPat { + span: self.token.span, + kw: box_span, + lo: box_span.shrink_to_lo(), + descr, + }); // We cannot use `parse_pat_ident()` since it will complain `box` // is not an identifier. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 6cceb47ff83..ae73760bd8c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -8,7 +8,7 @@ use rustc_ast::{ AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, Path, PathSegment, QSelf, }; -use rustc_errors::{pluralize, Applicability, PResult}; +use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym, Ident}; use std::mem; @@ -464,23 +464,10 @@ impl<'a> Parser<'a> { // i.e. no multibyte characters, in this range. let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)); - self.struct_span_err( + self.sess.emit_err(errors::UnmatchedAngle { span, - &format!( - "unmatched angle bracket{}", - pluralize!(snapshot.unmatched_angle_bracket_count) - ), - ) - .span_suggestion( - span, - &format!( - "remove extra angle bracket{}", - pluralize!(snapshot.unmatched_angle_bracket_count) - ), - "", - Applicability::MachineApplicable, - ) - .emit(); + plural: snapshot.unmatched_angle_bracket_count > 1, + }); // Try again without unmatched angle bracket characters. self.parse_angle_args(ty_generics) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index f5f6788362b..3ceb3a2bef1 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -588,20 +588,14 @@ impl<'a> Parser<'a> { // Always parse bounds greedily for better error recovery. if self.token.is_lifetime() { self.look_ahead(1, |t| { - if let token::Ident(symname, _) = t.kind { + if let token::Ident(sym, _) = t.kind { // parse pattern with "'a Sized" we're supposed to give suggestion like // "'a + Sized" - self.struct_span_err( - self.token.span, - &format!("expected `+` between lifetime and {}", symname), - ) - .span_suggestion_verbose( - self.token.span.shrink_to_hi(), - "add `+`", - " +", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(errors::MissingPlusBounds { + span: self.token.span, + hi: self.token.span.shrink_to_hi(), + sym, + }); } }) } @@ -926,14 +920,10 @@ impl<'a> Parser<'a> { self.parse_remaining_bounds(bounds, true)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let sp = vec![lo, self.prev_token.span]; - let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())]; - self.struct_span_err(sp, "incorrect braces around trait bounds") - .multipart_suggestion( - "remove the parentheses", - sugg, - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(errors::IncorrectBracesTraitBounds { + span: sp, + sugg: errors::IncorrectBracesTraitBoundsSugg { l: lo, r: self.prev_token.span }, + }); } else { self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 2f397e303e5..815b7c85679 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -1,6 +1,6 @@ //! Meta-syntax validation logic of attributes for post-expansion. -use crate::parse_in; +use crate::{errors, parse_in}; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::MetaItemKind; @@ -45,7 +45,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta kind: match &item.args { AttrArgs::Empty => MetaItemKind::Word, AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => { - check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); + check_meta_bad_delim(sess, *dspan, *delim); let nmis = parse_in(sess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?; MetaItemKind::List(nmis) } @@ -84,19 +84,24 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } -pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) { +pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) { if let ast::MacDelimiter::Parenthesis = delim { return; } + sess.emit_err(errors::MetaBadDelim { + span: span.entire(), + sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, + }); +} - sess.span_diagnostic - .struct_span_err(span.entire(), msg) - .multipart_suggestion( - "the delimiters should be `(` and `)`", - vec![(span.open, "(".to_string()), (span.close, ")".to_string())], - Applicability::MachineApplicable, - ) - .emit(); +pub fn check_cfg_attr_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) { + if let ast::MacDelimiter::Parenthesis = delim { + return; + } + sess.emit_err(errors::CfgAttrBadDelim { + span: span.entire(), + sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, + }); } /// Checks that the given meta-item is compatible with this `AttributeTemplate`. diff --git a/tests/ui/macros/missing-bang-in-decl.stderr b/tests/ui/macros/missing-bang-in-decl.stderr index dfabafb0a7a..aa78c9a6906 100644 --- a/tests/ui/macros/missing-bang-in-decl.stderr +++ b/tests/ui/macros/missing-bang-in-decl.stderr @@ -2,13 +2,23 @@ error: expected `!` after `macro_rules` --> $DIR/missing-bang-in-decl.rs:5:1 | LL | macro_rules foo { - | ^^^^^^^^^^^ help: add a `!`: `macro_rules!` + | ^^^^^^^^^^^ + | +help: add a `!` + | +LL | macro_rules! foo { + | + error: expected `!` after `macro_rules` --> $DIR/missing-bang-in-decl.rs:10:1 | LL | macro_rules bar! { - | ^^^^^^^^^^^ help: add a `!`: `macro_rules!` + | ^^^^^^^^^^^ + | +help: add a `!` + | +LL | macro_rules! bar! { + | + error: macro names aren't followed by a `!` --> $DIR/missing-bang-in-decl.rs:10:16 diff --git a/tests/ui/parser/item-kw-case-mismatch.fixed b/tests/ui/parser/item-kw-case-mismatch.fixed index 1794268f260..4b99537fbf7 100644 --- a/tests/ui/parser/item-kw-case-mismatch.fixed +++ b/tests/ui/parser/item-kw-case-mismatch.fixed @@ -4,31 +4,31 @@ fn main() {} -use std::ptr::read; //~ ERROR keyword `use` is written in a wrong case -use std::ptr::write; //~ ERROR keyword `use` is written in a wrong case +use std::ptr::read; //~ ERROR keyword `use` is written in the wrong case +use std::ptr::write; //~ ERROR keyword `use` is written in the wrong case async fn _a() {} -//~^ ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `fn` is written in the wrong case fn _b() {} -//~^ ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `fn` is written in the wrong case async fn _c() {} -//~^ ERROR keyword `async` is written in a wrong case -//~| ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `async` is written in the wrong case +//~| ERROR keyword `fn` is written in the wrong case async fn _d() {} -//~^ ERROR keyword `async` is written in a wrong case +//~^ ERROR keyword `async` is written in the wrong case const unsafe fn _e() {} -//~^ ERROR keyword `const` is written in a wrong case -//~| ERROR keyword `unsafe` is written in a wrong case -//~| ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `const` is written in the wrong case +//~| ERROR keyword `unsafe` is written in the wrong case +//~| ERROR keyword `fn` is written in the wrong case unsafe extern fn _f() {} -//~^ ERROR keyword `unsafe` is written in a wrong case -//~| ERROR keyword `extern` is written in a wrong case +//~^ ERROR keyword `unsafe` is written in the wrong case +//~| ERROR keyword `extern` is written in the wrong case extern "C" fn _g() {} -//~^ ERROR keyword `extern` is written in a wrong case -//~| ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `extern` is written in the wrong case +//~| ERROR keyword `fn` is written in the wrong case diff --git a/tests/ui/parser/item-kw-case-mismatch.rs b/tests/ui/parser/item-kw-case-mismatch.rs index ac8390efdb9..b11ec93754f 100644 --- a/tests/ui/parser/item-kw-case-mismatch.rs +++ b/tests/ui/parser/item-kw-case-mismatch.rs @@ -4,31 +4,31 @@ fn main() {} -Use std::ptr::read; //~ ERROR keyword `use` is written in a wrong case -USE std::ptr::write; //~ ERROR keyword `use` is written in a wrong case +Use std::ptr::read; //~ ERROR keyword `use` is written in the wrong case +USE std::ptr::write; //~ ERROR keyword `use` is written in the wrong case async Fn _a() {} -//~^ ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `fn` is written in the wrong case Fn _b() {} -//~^ ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `fn` is written in the wrong case aSYNC fN _c() {} -//~^ ERROR keyword `async` is written in a wrong case -//~| ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `async` is written in the wrong case +//~| ERROR keyword `fn` is written in the wrong case Async fn _d() {} -//~^ ERROR keyword `async` is written in a wrong case +//~^ ERROR keyword `async` is written in the wrong case CONST UNSAFE FN _e() {} -//~^ ERROR keyword `const` is written in a wrong case -//~| ERROR keyword `unsafe` is written in a wrong case -//~| ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `const` is written in the wrong case +//~| ERROR keyword `unsafe` is written in the wrong case +//~| ERROR keyword `fn` is written in the wrong case unSAFE EXTern fn _f() {} -//~^ ERROR keyword `unsafe` is written in a wrong case -//~| ERROR keyword `extern` is written in a wrong case +//~^ ERROR keyword `unsafe` is written in the wrong case +//~| ERROR keyword `extern` is written in the wrong case EXTERN "C" FN _g() {} -//~^ ERROR keyword `extern` is written in a wrong case -//~| ERROR keyword `fn` is written in a wrong case +//~^ ERROR keyword `extern` is written in the wrong case +//~| ERROR keyword `fn` is written in the wrong case diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr index e66dae825f9..ba59ea85363 100644 --- a/tests/ui/parser/item-kw-case-mismatch.stderr +++ b/tests/ui/parser/item-kw-case-mismatch.stderr @@ -1,82 +1,82 @@ -error: keyword `use` is written in a wrong case +error: keyword `use` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:7:1 | LL | Use std::ptr::read; | ^^^ help: write it in the correct case (notice the capitalization): `use` -error: keyword `use` is written in a wrong case +error: keyword `use` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:8:1 | LL | USE std::ptr::write; | ^^^ help: write it in the correct case: `use` -error: keyword `fn` is written in a wrong case +error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:10:7 | LL | async Fn _a() {} | ^^ help: write it in the correct case (notice the capitalization): `fn` -error: keyword `fn` is written in a wrong case +error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:13:1 | LL | Fn _b() {} | ^^ help: write it in the correct case (notice the capitalization): `fn` -error: keyword `async` is written in a wrong case +error: keyword `async` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:16:1 | LL | aSYNC fN _c() {} | ^^^^^ help: write it in the correct case: `async` -error: keyword `fn` is written in a wrong case +error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:16:7 | LL | aSYNC fN _c() {} | ^^ help: write it in the correct case: `fn` -error: keyword `async` is written in a wrong case +error: keyword `async` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:20:1 | LL | Async fn _d() {} | ^^^^^ help: write it in the correct case: `async` -error: keyword `const` is written in a wrong case +error: keyword `const` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:1 | LL | CONST UNSAFE FN _e() {} | ^^^^^ help: write it in the correct case: `const` -error: keyword `unsafe` is written in a wrong case +error: keyword `unsafe` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:7 | LL | CONST UNSAFE FN _e() {} | ^^^^^^ help: write it in the correct case: `unsafe` -error: keyword `fn` is written in a wrong case +error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:23:14 | LL | CONST UNSAFE FN _e() {} | ^^ help: write it in the correct case: `fn` -error: keyword `unsafe` is written in a wrong case +error: keyword `unsafe` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:28:1 | LL | unSAFE EXTern fn _f() {} | ^^^^^^ help: write it in the correct case: `unsafe` -error: keyword `extern` is written in a wrong case +error: keyword `extern` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:28:8 | LL | unSAFE EXTern fn _f() {} | ^^^^^^ help: write it in the correct case: `extern` -error: keyword `extern` is written in a wrong case +error: keyword `extern` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:32:1 | LL | EXTERN "C" FN _g() {} | ^^^^^^ help: write it in the correct case: `extern` -error: keyword `fn` is written in a wrong case +error: keyword `fn` is written in the wrong case --> $DIR/item-kw-case-mismatch.rs:32:12 | LL | EXTERN "C" FN _g() {} diff --git a/tests/ui/parser/recover-unticked-labels.stderr b/tests/ui/parser/recover-unticked-labels.stderr index c115dffb10e..fbd108ca613 100644 --- a/tests/ui/parser/recover-unticked-labels.stderr +++ b/tests/ui/parser/recover-unticked-labels.stderr @@ -2,13 +2,17 @@ error: expected a label, found an identifier --> $DIR/recover-unticked-labels.rs:5:26 | LL | 'label: loop { break label 0 }; - | ^^^^^ help: labels start with a tick: `'label` + | -^^^^ + | | + | help: labels start with a tick error: expected a label, found an identifier --> $DIR/recover-unticked-labels.rs:6:29 | LL | 'label: loop { continue label }; - | ^^^^^ help: labels start with a tick: `'label` + | -^^^^ + | | + | help: labels start with a tick error[E0425]: cannot find value `label` in this scope --> $DIR/recover-unticked-labels.rs:4:26 diff --git a/tests/ui/parser/use-colon-as-mod-sep.stderr b/tests/ui/parser/use-colon-as-mod-sep.stderr index e825dfed111..bfc5374ef9d 100644 --- a/tests/ui/parser/use-colon-as-mod-sep.stderr +++ b/tests/ui/parser/use-colon-as-mod-sep.stderr @@ -11,18 +11,24 @@ error: expected `::`, found `:` | LL | use std:fs::File; | ^ help: use double colon + | + = note: import paths are delimited using `::` error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:7:8 | LL | use std:collections:HashMap; | ^ help: use double colon + | + = note: import paths are delimited using `::` error: expected `::`, found `:` --> $DIR/use-colon-as-mod-sep.rs:7:20 | LL | use std:collections:HashMap; | ^ help: use double colon + | + = note: import paths are delimited using `::` error: aborting due to 4 previous errors From 52ff751aa4094c808a39d8e4cd9e5f0d1ea7974a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 27 Apr 2023 16:42:17 +0200 Subject: [PATCH 06/12] pub -> pub(super). --- library/core/src/fmt/rt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 8498f5f5a7c..0596f6c30ce 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -54,7 +54,7 @@ pub enum Count { // This needs to match the order of flags in compiler/rustc_ast_lowering/src/format.rs. #[derive(Copy, Clone)] -pub enum Flag { +pub(super) enum Flag { SignPlus, SignMinus, Alternate, From 34d96886d48a9d7deb53ae1f6a13b571b5caeb78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 27 Apr 2023 18:12:53 +0200 Subject: [PATCH 07/12] rustdoc: rebind bound vars to type-outlives predicates --- src/librustdoc/clean/mod.rs | 10 +++++----- tests/rustdoc-ui/issue-110900.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 tests/rustdoc-ui/issue-110900.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 04379c2bca9..0f5ac93a0a8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -304,7 +304,7 @@ pub(crate) fn clean_predicate<'tcx>( clean_region_outlives_predicate(pred) } ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => { - clean_type_outlives_predicate(pred, cx) + clean_type_outlives_predicate(bound_predicate.rebind(pred), cx) } ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { Some(clean_projection_predicate(bound_predicate.rebind(pred), cx)) @@ -345,7 +345,7 @@ fn clean_poly_trait_predicate<'tcx>( } fn clean_region_outlives_predicate<'tcx>( - pred: ty::OutlivesPredicate, ty::Region<'tcx>>, + pred: ty::RegionOutlivesPredicate<'tcx>, ) -> Option { let ty::OutlivesPredicate(a, b) = pred; @@ -358,13 +358,13 @@ fn clean_region_outlives_predicate<'tcx>( } fn clean_type_outlives_predicate<'tcx>( - pred: ty::OutlivesPredicate, ty::Region<'tcx>>, + pred: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>, cx: &mut DocContext<'tcx>, ) -> Option { - let ty::OutlivesPredicate(ty, lt) = pred; + let ty::OutlivesPredicate(ty, lt) = pred.skip_binder(); Some(WherePredicate::BoundPredicate { - ty: clean_middle_ty(ty::Binder::dummy(ty), cx, None), + ty: clean_middle_ty(pred.rebind(ty), cx, None), bounds: vec![GenericBound::Outlives( clean_middle_region(lt).expect("failed to clean lifetimes"), )], diff --git a/tests/rustdoc-ui/issue-110900.rs b/tests/rustdoc-ui/issue-110900.rs new file mode 100644 index 00000000000..e3154baf860 --- /dev/null +++ b/tests/rustdoc-ui/issue-110900.rs @@ -0,0 +1,28 @@ +// check-pass + +#![crate_type="lib"] +#![feature(associated_type_bounds)] + +trait A<'a> {} +trait B<'b> {} + +trait C<'c>: for<'a> A<'a> + for<'b> B<'b> { + type As; +} + +trait E<'e> { + type As; +} +trait F<'f>: for<'a> A<'a> + for<'e> E<'e> {} +struct G +where + T: for<'l, 'i> H<'l, 'i, As: for<'a> A<'a> + 'i> +{ + t: std::marker::PhantomData, +} + +trait I<'a, 'b, 'c> { + type As; +} + +trait H<'d, 'e>: for<'f> I<'d, 'f, 'e> + 'd {} From 183c7904e981a1b3bbfb4d9ab2e9ce78f5c1ea34 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Apr 2023 18:33:39 +0000 Subject: [PATCH 08/12] Add invalid_macro_export_arguments to built-in macro list --- compiler/rustc_lint_defs/src/builtin.rs | 1 + .../invalid_macro_export_argument.deny.stderr | 20 +++++++++++++++++++ .../invalid_macro_export_argument.rs | 13 +++++++++--- .../invalid_macro_export_argument.stderr | 16 --------------- 4 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 tests/ui/attributes/invalid_macro_export_argument.deny.stderr delete mode 100644 tests/ui/attributes/invalid_macro_export_argument.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b223b8c137a..90604f650d3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3377,6 +3377,7 @@ declare_lint_pass! { IMPLIED_BOUNDS_ENTAILMENT, BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, AMBIGUOUS_GLOB_REEXPORTS, + INVALID_MACRO_EXPORT_ARGUMENTS, ] } diff --git a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr new file mode 100644 index 00000000000..644acc27b58 --- /dev/null +++ b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr @@ -0,0 +1,20 @@ +error: `#[macro_export]` can only take 1 or 0 arguments + --> $DIR/invalid_macro_export_argument.rs:7:1 + | +LL | #[macro_export(hello, world)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/invalid_macro_export_argument.rs:4:24 + | +LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `not_local_inner_macros` isn't a valid `#[macro_export]` argument + --> $DIR/invalid_macro_export_argument.rs:13:16 + | +LL | #[macro_export(not_local_inner_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/attributes/invalid_macro_export_argument.rs b/tests/ui/attributes/invalid_macro_export_argument.rs index 85d009f11a6..a0ed5fd1c8f 100644 --- a/tests/ui/attributes/invalid_macro_export_argument.rs +++ b/tests/ui/attributes/invalid_macro_export_argument.rs @@ -1,10 +1,17 @@ -// check-pass -#[macro_export(hello, world)] //~ WARN `#[macro_export]` can only take 1 or 0 arguments +// revisions: deny allow +//[allow] check-pass + +#![cfg_attr(deny, deny(invalid_macro_export_arguments))] +#![cfg_attr(allow, allow(invalid_macro_export_arguments))] + +#[macro_export(hello, world)] +//[deny]~^ ERROR `#[macro_export]` can only take 1 or 0 arguments macro_rules! a { () => () } -#[macro_export(not_local_inner_macros)] //~ WARN `not_local_inner_macros` isn't a valid `#[macro_export]` argument +#[macro_export(not_local_inner_macros)] +//[deny]~^ ERROR `not_local_inner_macros` isn't a valid `#[macro_export]` argument macro_rules! b { () => () } diff --git a/tests/ui/attributes/invalid_macro_export_argument.stderr b/tests/ui/attributes/invalid_macro_export_argument.stderr deleted file mode 100644 index a4e17642c2a..00000000000 --- a/tests/ui/attributes/invalid_macro_export_argument.stderr +++ /dev/null @@ -1,16 +0,0 @@ -warning: `#[macro_export]` can only take 1 or 0 arguments - --> $DIR/invalid_macro_export_argument.rs:2:1 - | -LL | #[macro_export(hello, world)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(invalid_macro_export_arguments)]` on by default - -warning: `not_local_inner_macros` isn't a valid `#[macro_export]` argument - --> $DIR/invalid_macro_export_argument.rs:7:16 - | -LL | #[macro_export(not_local_inner_macros)] - | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: 2 warnings emitted - From 3793263c7dd746dc26ca99db64eb9203b804b87a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Apr 2023 18:35:27 +0000 Subject: [PATCH 09/12] Sort hardwired lints --- compiler/rustc_lint_defs/src/builtin.rs | 192 ++++++++++++------------ 1 file changed, 97 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 90604f650d3..a33341cec33 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3273,111 +3273,113 @@ declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. HardwiredLints => [ - FORBIDDEN_LINT_GROUPS, - ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + // tidy-alphabetical-start + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + AMBIGUOUS_ASSOCIATED_ITEMS, + AMBIGUOUS_GLOB_REEXPORTS, ARITHMETIC_OVERFLOW, - UNCONDITIONAL_PANIC, - UNUSED_IMPORTS, - UNUSED_EXTERN_CRATES, - UNUSED_CRATE_DEPENDENCIES, - UNUSED_QUALIFICATIONS, - UNKNOWN_LINTS, - UNFULFILLED_LINT_EXPECTATIONS, - UNUSED_VARIABLES, - UNUSED_ASSIGNMENTS, - DEAD_CODE, - UNREACHABLE_CODE, - UNREACHABLE_PATTERNS, - OVERLAPPING_RANGE_ENDPOINTS, + ASM_SUB_REGISTER, + BAD_ASM_STYLE, + BARE_TRAIT_OBJECTS, BINDINGS_WITH_VARIANT_NAME, - UNUSED_MACROS, - UNUSED_MACRO_RULES, - WARNINGS, - UNUSED_FEATURES, + BREAK_WITH_LABEL_AND_LOOP, + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + CENUM_IMPL_DROP_CAST, + COHERENCE_LEAK_CHECK, + CONFLICTING_REPR_HINTS, + CONST_EVALUATABLE_UNCHECKED, + CONST_ITEM_MUTATION, + DEAD_CODE, + DEPRECATED, + DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, + DEPRECATED_IN_FUTURE, + DEPRECATED_WHERE_CLAUSE_LOCATION, + DUPLICATE_MACRO_ATTRIBUTES, + ELIDED_LIFETIMES_IN_PATHS, + EXPORTED_PRIVATE_DEPENDENCIES, + FFI_UNWIND_CALLS, + FORBIDDEN_LINT_GROUPS, + FUNCTION_ITEM_REFERENCES, + FUZZY_PROVENANCE_CASTS, + ILL_FORMED_ATTRIBUTE_INPUT, + ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + IMPLIED_BOUNDS_ENTAILMENT, + INCOMPLETE_INCLUDE, + INDIRECT_STRUCTURAL_MATCH, + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + INLINE_NO_SANITIZE, + INVALID_DOC_ATTRIBUTES, + INVALID_MACRO_EXPORT_ARGUMENTS, + INVALID_TYPE_PARAM_DEFAULT, + IRREFUTABLE_LET_PATTERNS, + LARGE_ASSIGNMENTS, + LATE_BOUND_LIFETIME_ARGUMENTS, + LEGACY_DERIVE_HELPERS, + LOSSY_PROVENANCE_CASTS, + MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + MACRO_USE_EXTERN_CRATE, + META_VARIABLE_MISUSE, + MISSING_ABI, + MISSING_FRAGMENT_SPECIFIER, + MUST_NOT_SUSPEND, + NAMED_ARGUMENTS_USED_POSITIONALLY, + NON_EXHAUSTIVE_OMITTED_PATTERNS, + NONTRIVIAL_STRUCTURAL_MATCH, + ORDER_DEPENDENT_TRAIT_OBJECTS, + OVERLAPPING_RANGE_ENDPOINTS, + PATTERNS_IN_FNS_WITHOUT_BODY, + POINTER_STRUCTURAL_MATCH, + PRIVATE_IN_PUBLIC, + PROC_MACRO_BACK_COMPAT, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, + RENAMED_AND_REMOVED_LINTS, + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, + RUST_2021_INCOMPATIBLE_OR_PATTERNS, + RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, + RUST_2021_PRELUDE_COLLISIONS, + SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, + SINGLE_USE_LIFETIMES, + SOFT_UNSTABLE, STABLE_FEATURES, - UNKNOWN_CRATE_TYPES, + SUSPICIOUS_AUTO_TRAIT_IMPLS, + TEST_UNSTABLE_LINT, + TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TRIVIAL_CASTS, TRIVIAL_NUMERIC_CASTS, - PRIVATE_IN_PUBLIC, - EXPORTED_PRIVATE_DEPENDENCIES, - PUB_USE_OF_PRIVATE_EXTERN_CRATE, - INVALID_TYPE_PARAM_DEFAULT, - RENAMED_AND_REMOVED_LINTS, - CONST_ITEM_MUTATION, - PATTERNS_IN_FNS_WITHOUT_BODY, - MISSING_FRAGMENT_SPECIFIER, - LATE_BOUND_LIFETIME_ARGUMENTS, - ORDER_DEPENDENT_TRAIT_OBJECTS, - COHERENCE_LEAK_CHECK, - DEPRECATED, - UNUSED_UNSAFE, - UNUSED_MUT, - UNCONDITIONAL_RECURSION, - SINGLE_USE_LIFETIMES, - UNUSED_LIFETIMES, - UNUSED_LABELS, TYVAR_BEHIND_RAW_POINTER, - ELIDED_LIFETIMES_IN_PATHS, - BARE_TRAIT_OBJECTS, - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - UNSTABLE_NAME_COLLISIONS, - IRREFUTABLE_LET_PATTERNS, - WHERE_CLAUSES_OBJECT_SAFETY, - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - MACRO_USE_EXTERN_CRATE, - MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - ILL_FORMED_ATTRIBUTE_INPUT, - CONFLICTING_REPR_HINTS, - META_VARIABLE_MISUSE, - DEPRECATED_IN_FUTURE, - AMBIGUOUS_ASSOCIATED_ITEMS, - INDIRECT_STRUCTURAL_MATCH, - POINTER_STRUCTURAL_MATCH, - NONTRIVIAL_STRUCTURAL_MATCH, - SOFT_UNSTABLE, - UNSTABLE_SYNTAX_PRE_EXPANSION, - INLINE_NO_SANITIZE, - BAD_ASM_STYLE, - ASM_SUB_REGISTER, - UNSAFE_OP_IN_UNSAFE_FN, - INCOMPLETE_INCLUDE, - CENUM_IMPL_DROP_CAST, - FUZZY_PROVENANCE_CASTS, - LOSSY_PROVENANCE_CASTS, - CONST_EVALUATABLE_UNCHECKED, - INEFFECTIVE_UNSTABLE_TRAIT_IMPL, - MUST_NOT_SUSPEND, + UNCONDITIONAL_PANIC, + UNCONDITIONAL_RECURSION, + UNFULFILLED_LINT_EXPECTATIONS, UNINHABITED_STATIC, - FUNCTION_ITEM_REFERENCES, - USELESS_DEPRECATED, - MISSING_ABI, - INVALID_DOC_ATTRIBUTES, - SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, - RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, - LEGACY_DERIVE_HELPERS, - PROC_MACRO_BACK_COMPAT, - RUST_2021_INCOMPATIBLE_OR_PATTERNS, - LARGE_ASSIGNMENTS, - RUST_2021_PRELUDE_COLLISIONS, - RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, + UNKNOWN_CRATE_TYPES, + UNKNOWN_LINTS, + UNREACHABLE_CODE, + UNREACHABLE_PATTERNS, + UNSAFE_OP_IN_UNSAFE_FN, + UNSTABLE_NAME_COLLISIONS, + UNSTABLE_SYNTAX_PRE_EXPANSION, UNSUPPORTED_CALLING_CONVENTIONS, - BREAK_WITH_LABEL_AND_LOOP, + UNUSED_ASSIGNMENTS, UNUSED_ATTRIBUTES, + UNUSED_CRATE_DEPENDENCIES, + UNUSED_EXTERN_CRATES, + UNUSED_FEATURES, + UNUSED_IMPORTS, + UNUSED_LABELS, + UNUSED_LIFETIMES, + UNUSED_MACRO_RULES, + UNUSED_MACROS, + UNUSED_MUT, + UNUSED_QUALIFICATIONS, UNUSED_TUPLE_STRUCT_FIELDS, - NON_EXHAUSTIVE_OMITTED_PATTERNS, - TEXT_DIRECTION_CODEPOINT_IN_COMMENT, - DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - DUPLICATE_MACRO_ATTRIBUTES, - SUSPICIOUS_AUTO_TRAIT_IMPLS, - DEPRECATED_WHERE_CLAUSE_LOCATION, - TEST_UNSTABLE_LINT, - FFI_UNWIND_CALLS, - REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, - NAMED_ARGUMENTS_USED_POSITIONALLY, - IMPLIED_BOUNDS_ENTAILMENT, - BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, - AMBIGUOUS_GLOB_REEXPORTS, - INVALID_MACRO_EXPORT_ARGUMENTS, + UNUSED_UNSAFE, + UNUSED_VARIABLES, + USELESS_DEPRECATED, + WARNINGS, + WHERE_CLAUSES_OBJECT_SAFETY, + // tidy-alphabetical-end ] } From 0279922157761fa103c6be1792d2c3f77e5a61a3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 27 Apr 2023 18:43:03 +0000 Subject: [PATCH 10/12] Add a few more missing lints --- compiler/rustc_lint_defs/src/builtin.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a33341cec33..a3d7bd3ef59 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3308,6 +3308,7 @@ declare_lint_pass! { INDIRECT_STRUCTURAL_MATCH, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, INLINE_NO_SANITIZE, + INVALID_ALIGNMENT, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, INVALID_TYPE_PARAM_DEFAULT, @@ -3351,6 +3352,7 @@ declare_lint_pass! { TYVAR_BEHIND_RAW_POINTER, UNCONDITIONAL_PANIC, UNCONDITIONAL_RECURSION, + UNDEFINED_NAKED_FUNCTION_ABI, UNFULFILLED_LINT_EXPECTATIONS, UNINHABITED_STATIC, UNKNOWN_CRATE_TYPES, From ddff7f0e50c1184c5cfa1a54c7bd2b6848ed85d6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 28 Apr 2023 02:19:00 +0100 Subject: [PATCH 11/12] remove_dir_all: delete directory with fewer perms If opening a directory with `FILE_LIST_DIRECTORY` access fails then we should try opening without requesting that access. We may still be able to delete it if it's empty or a link. --- library/std/src/sys/windows/fs.rs | 41 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 956db577d53..8ed62cdddcd 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1132,27 +1132,30 @@ fn remove_dir_all_iterative(f: &File, delete: fn(&File) -> io::Result<()>) -> io &dir, &name, c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY, - )?; - dirlist.push(child_dir); - } else { - for i in 1..=MAX_RETRIES { - let result = open_link_no_reparse(&dir, &name, c::SYNCHRONIZE | c::DELETE); - match result { - Ok(f) => delete(&f)?, - // Already deleted, so skip. - Err(e) if e.kind() == io::ErrorKind::NotFound => break, - // Retry a few times if the file is locked or a delete is already in progress. - Err(e) - if i < MAX_RETRIES - && (e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _) - || e.raw_os_error() - == Some(c::ERROR_SHARING_VIOLATION as _)) => {} - // Otherwise return the error. - Err(e) => return Err(e), - } - thread::yield_now(); + ); + // On success, add the handle to the queue. + // If opening the directory fails we treat it the same as a file + if let Ok(child_dir) = child_dir { + dirlist.push(child_dir); + continue; } } + for i in 1..=MAX_RETRIES { + let result = open_link_no_reparse(&dir, &name, c::SYNCHRONIZE | c::DELETE); + match result { + Ok(f) => delete(&f)?, + // Already deleted, so skip. + Err(e) if e.kind() == io::ErrorKind::NotFound => break, + // Retry a few times if the file is locked or a delete is already in progress. + Err(e) + if i < MAX_RETRIES + && (e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _) + || e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _)) => {} + // Otherwise return the error. + Err(e) => return Err(e), + } + thread::yield_now(); + } } // If there were no more files then delete the directory. if !more_data { From 176144e821fa3c0c18c6073cf89cd5ddb7a9e8cb Mon Sep 17 00:00:00 2001 From: cui fliter Date: Fri, 28 Apr 2023 09:54:35 +0800 Subject: [PATCH 12/12] Fix unavailable url Signed-off-by: cui fliter --- src/etc/lldb_providers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 4f73746f817..c4381e202b9 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -31,7 +31,7 @@ from lldb import SBValue, SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLon # # You can find more information and examples here: # 1. https://lldb.llvm.org/varformats.html -# 2. https://lldb.llvm.org/python-reference.html +# 2. https://lldb.llvm.org/use/python-reference.html # 3. https://lldb.llvm.org/python_reference/lldb.formatters.cpp.libcxx-pysrc.html # 4. https://github.com/llvm-mirror/lldb/tree/master/examples/summaries/cocoa ####################################################################################################