diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 2484f817a06f8..c690789b587f6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -575,7 +575,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // ---------- place self.err.multipart_suggestions( format!( - "to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API", + "use `.insert()` to insert a value into a `{}`, `.get_mut()` \ + to modify it, or the entry API for more flexibility", self.ty, ), vec![ @@ -592,16 +593,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { (rv.span.shrink_to_hi(), ")".to_string()), ], vec![ - // val.get_mut(index).map(|v| { *v = rv; }); + // if let Some(v) = val.get_mut(index) { *v = rv; } + (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()), ( val.span.shrink_to_hi().with_hi(index.span.lo()), ".get_mut(".to_string(), ), ( index.span.shrink_to_hi().with_hi(place.span.hi()), - ").map(|val| { *val".to_string(), + ") { *val".to_string(), ), - (rv.span.shrink_to_hi(), "; })".to_string()), + (rv.span.shrink_to_hi(), "; }".to_string()), ], vec![ // let x = val.entry(index).or_insert(rv); @@ -622,21 +624,22 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggested = true; } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind && let hir::ExprKind::Index(val, index, _) = receiver.kind - && expr.span == self.assign_span + && receiver.span == self.assign_span { // val[index].path(args..); self.err.multipart_suggestion( format!("to modify a `{}` use `.get_mut()`", self.ty), vec![ + (val.span.shrink_to_lo(), "if let Some(val) = ".to_string()), ( val.span.shrink_to_hi().with_hi(index.span.lo()), ".get_mut(".to_string(), ), ( index.span.shrink_to_hi().with_hi(receiver.span.hi()), - ").map(|val| val".to_string(), + ") { val".to_string(), ), - (sp.shrink_to_hi(), ")".to_string()), + (sp.shrink_to_hi(), "; }".to_string()), ], Applicability::MachineApplicable, ); diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 7a31d2a223917..4cac7cb93f581 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -197,6 +197,8 @@ builtin_macros_format_redundant_args = redundant {$n -> builtin_macros_format_remove_raw_ident = remove the `r#` +builtin_macros_format_reorder_format_parameter = did you mean `{$replacement}`? + builtin_macros_format_requires_string = requires at least a format string argument builtin_macros_format_string_invalid = invalid format string: {$desc} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 1abdfdb9c65c9..6213bd802c751 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -618,6 +618,17 @@ pub(crate) enum InvalidFormatStringSuggestion { #[primary_span] span: Span, }, + #[suggestion( + builtin_macros_format_reorder_format_parameter, + code = "{replacement}", + style = "verbose", + applicability = "machine-applicable" + )] + ReorderFormatParameter { + #[primary_span] + span: Span, + replacement: String, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 0112499c50949..5202fe26c401e 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -321,6 +321,13 @@ fn make_format_args( e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span }) } } + parse::Suggestion::ReorderFormatParameter(span, replacement) => { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = Some(errors::InvalidFormatStringSuggestion::ReorderFormatParameter { + span, + replacement, + }); + } } let guar = ecx.dcx().emit_err(e); return ExpandResult::Ready(Err(guar)); diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs index d4f8199390cc5..08b7d937661fb 100644 --- a/compiler/rustc_driver_impl/src/signal_handler.rs +++ b/compiler/rustc_driver_impl/src/signal_handler.rs @@ -2,7 +2,7 @@ //! Primarily used to extract a backtrace from stack overflow use std::alloc::{Layout, alloc}; -use std::{fmt, mem, ptr}; +use std::{fmt, mem, ptr, slice}; use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE}; @@ -35,20 +35,22 @@ macro raw_errln($tokens:tt) { } /// Signal handler installed for SIGSEGV -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#[allow(static_mut_refs)] -extern "C" fn print_stack_trace(_: libc::c_int) { +/// +/// # Safety +/// +/// Caller must ensure that this function is not re-entered. +unsafe extern "C" fn print_stack_trace(_: libc::c_int) { const MAX_FRAMES: usize = 256; - // Reserve data segment so we don't have to malloc in a signal handler, which might fail - // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking - static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES]; let stack = unsafe { + // Reserve data segment so we don't have to malloc in a signal handler, which might fail + // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking + static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES]; // Collect return addresses - let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32); + let depth = libc::backtrace(&raw mut STACK_TRACE as _, MAX_FRAMES as i32); if depth == 0 { return; } - &STACK_TRACE.as_slice()[0..(depth as _)] + slice::from_raw_parts(&raw const STACK_TRACE as _, depth as _) }; // Just a stack trace is cryptic. Explain what we're doing. diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index d95cbb051580b..bae9defa68700 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -1,9 +1,11 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_errors::Diag; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_middle::ty; +use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::Symbol; +use rustc_span::def_id::DefId; use rustc_span::symbol::sym; use crate::{LateContext, LateLintPass}; @@ -149,13 +151,16 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { let hir_id = cx.tcx.local_def_id_to_hir_id(local); let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return }; cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| { - mk_lint(diag, orig_fields, fields); + mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields); }); } } fn mk_lint( + tcx: TyCtxt<'_>, diag: &mut Diag<'_, ()>, + type_def_id: DefId, + impl_def_id: DefId, orig_fields: FxHashMap>, fields: &[hir::ExprField<'_>], ) { @@ -175,11 +180,24 @@ fn mk_lint( } } - diag.help(if removed_all_fields { - "to avoid divergence in behavior between `Struct { .. }` and \ - `::default()`, derive the `Default`" + if removed_all_fields { + let msg = "to avoid divergence in behavior between `Struct { .. }` and \ + `::default()`, derive the `Default`"; + if let Some(hir::Node::Item(impl_)) = tcx.hir().get_if_local(impl_def_id) { + diag.multipart_suggestion_verbose( + msg, + vec![ + (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()), + (impl_.span, String::new()), + ], + Applicability::MachineApplicable, + ); + } else { + diag.help(msg); + } } else { - "use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them \ - diverging over time" - }); + let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \ + avoid them diverging over time"; + diag.help(msg); + } } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 1716f417969e1..9eb335cb34cc2 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -221,6 +221,11 @@ pub enum Suggestion { /// Remove `r#` from identifier: /// `format!("{r#foo}")` -> `format!("{foo}")` RemoveRawIdent(InnerSpan), + /// Reorder format parameter: + /// `format!("{foo:?#}")` -> `format!("{foo:#?}")` + /// `format!("{foo:?x}")` -> `format!("{foo:x?}")` + /// `format!("{foo:?X}")` -> `format!("{foo:X?}")` + ReorderFormatParameter(InnerSpan, string::String), } /// The parser structure for interpreting the input format string. This is @@ -731,6 +736,12 @@ impl<'a> Parser<'a> { } } else if self.consume('?') { spec.ty = "?"; + if let Some(&(_, maybe)) = self.cur.peek() { + match maybe { + '#' | 'x' | 'X' => self.suggest_format_parameter(maybe), + _ => (), + } + } } else { spec.ty = self.word(); if !spec.ty.is_empty() { @@ -932,6 +943,30 @@ impl<'a> Parser<'a> { } } } + + fn suggest_format_parameter(&mut self, c: char) { + let replacement = match c { + '#' => "#?", + 'x' => "x?", + 'X' => "X?", + _ => return, + }; + let Some(pos) = self.consume_pos(c) else { + return; + }; + + let span = self.span(pos - 1, pos + 1); + let pos = self.to_span_index(pos); + + self.errors.insert(0, ParseError { + description: format!("expected `}}`, found `{c}`"), + note: None, + label: "expected `'}'`".into(), + span: pos.to(pos), + secondary_label: None, + suggestion: Suggestion::ReorderFormatParameter(span, format!("{replacement}")), + }) + } } /// Finds the indices of all characters that have been processed and differ between the actual diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 6a8f7f4ee3513..1b8b35f18df84 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -445,9 +445,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - /// When after several dereferencing, the reference satisfies the trait - /// bound. This function provides dereference suggestion for this - /// specific situation. + /// Provide a suggestion to dereference arguments to functions and binary operators, if that + /// would satisfy trait bounds. pub(super) fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, @@ -461,127 +460,100 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) { // Suggest dereferencing the argument to a function/method call if possible + + // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437) let mut real_trait_pred = trait_pred; while let Some((parent_code, parent_trait_pred)) = code.parent() { code = parent_code; if let Some(parent_trait_pred) = parent_trait_pred { real_trait_pred = parent_trait_pred; } + } - // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle - // `ReBound`, and we don't particularly care about the regions. - let real_ty = - self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty()); + // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle + // `ReBound`, and we don't particularly care about the regions. + let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty()); + if !self.can_eq(obligation.param_env, real_ty, arg_ty) { + return false; + } - if self.can_eq(obligation.param_env, real_ty, arg_ty) - && let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() + // Potentially, we'll want to place our dereferences under a `&`. We don't try this for + // `&mut`, since we can't be sure users will get the side-effects they want from it. + // If this doesn't work, we'll try removing the `&` in `suggest_remove_reference`. + // FIXME(dianne): this misses the case where users need both to deref and remove `&`s. + // This method could be combined with `TypeErrCtxt::suggest_remove_reference` to handle + // that, similar to what `FnCtxt::suggest_deref_or_ref` does. + let (is_under_ref, base_ty, span) = match expr.kind { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, subexpr) + if let &ty::Ref(region, base_ty, hir::Mutability::Not) = real_ty.kind() => { - let autoderef = (self.autoderef_steps)(base_ty); - if let Some(steps) = - autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| { - // Re-add the `&` - let ty = Ty::new_ref(self.tcx, region, ty, mutbl); - - // Remapping bound vars here - let real_trait_pred_and_ty = real_trait_pred - .map_bound(|inner_trait_pred| (inner_trait_pred, ty)); - let obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - real_trait_pred_and_ty, - ); - let may_hold = obligations - .iter() - .chain([&obligation]) - .all(|obligation| self.predicate_may_hold(obligation)) - .then_some(steps); + (Some(region), base_ty, subexpr.span) + } + // Don't suggest `*&mut`, etc. + hir::ExprKind::AddrOf(..) => return false, + _ => (None, real_ty, obligation.cause.span), + }; - may_hold - }) - { - if steps > 0 { - // Don't care about `&mut` because `DerefMut` is used less - // often and user will not expect that an autoderef happens. - if let hir::Node::Expr(hir::Expr { - kind: - hir::ExprKind::AddrOf( - hir::BorrowKind::Ref, - hir::Mutability::Not, - expr, - ), - .. - }) = self.tcx.hir_node(*arg_hir_id) - { - let derefs = "*".repeat(steps); - err.span_suggestion_verbose( - expr.span.shrink_to_lo(), - "consider dereferencing here", - derefs, - Applicability::MachineApplicable, - ); - return true; - } - } - } else if real_trait_pred != trait_pred { - // This branch addresses #87437. - - let span = obligation.cause.span; - // Remapping bound vars here - let real_trait_pred_and_base_ty = real_trait_pred - .map_bound(|inner_trait_pred| (inner_trait_pred, base_ty)); - let obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - real_trait_pred_and_base_ty, - ); - let sized_obligation = Obligation::new( - self.tcx, - obligation.cause.clone(), - obligation.param_env, - ty::TraitRef::new( - self.tcx, - self.tcx.require_lang_item( - hir::LangItem::Sized, - Some(obligation.cause.span), - ), - [base_ty], - ), - ); - if self.predicate_may_hold(&obligation) - && self.predicate_must_hold_modulo_regions(&sized_obligation) - // Do not suggest * if it is already a reference, - // will suggest removing the borrow instead in that case. - && !matches!(expr.kind, hir::ExprKind::AddrOf(..)) - { - let call_node = self.tcx.hir_node(*call_hir_id); - let msg = "consider dereferencing here"; - let is_receiver = matches!( - call_node, - Node::Expr(hir::Expr { - kind: hir::ExprKind::MethodCall(_, receiver_expr, ..), - .. - }) - if receiver_expr.hir_id == *arg_hir_id - ); - if is_receiver { - err.multipart_suggestion_verbose( - msg, - vec![ - (span.shrink_to_lo(), "(*".to_string()), - (span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ) - } else { - err.span_suggestion_verbose( - span.shrink_to_lo(), - msg, - '*', - Applicability::MachineApplicable, - ) - }; - return true; - } - } + let autoderef = (self.autoderef_steps)(base_ty); + let mut is_boxed = base_ty.is_box(); + if let Some(steps) = autoderef.into_iter().position(|(mut ty, obligations)| { + // Ensure one of the following for dereferencing to be valid: we're passing by + // reference, `ty` is `Copy`, or we're moving out of a (potentially nested) `Box`. + let can_deref = is_under_ref.is_some() + || self.type_is_copy_modulo_regions(obligation.param_env, ty) + || ty.is_numeric() // for inference vars (presumably but not provably `Copy`) + || is_boxed && self.type_is_sized_modulo_regions(obligation.param_env, ty); + is_boxed &= ty.is_box(); + + // Re-add the `&` if necessary + if let Some(region) = is_under_ref { + ty = Ty::new_ref(self.tcx, region, ty, hir::Mutability::Not); } + + // Remapping bound vars here + let real_trait_pred_and_ty = + real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty)); + let obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + real_trait_pred_and_ty, + ); + + can_deref + && obligations + .iter() + .chain([&obligation]) + .all(|obligation| self.predicate_may_hold(obligation)) + }) && steps > 0 + { + let derefs = "*".repeat(steps); + let msg = "consider dereferencing here"; + let call_node = self.tcx.hir_node(*call_hir_id); + let is_receiver = matches!( + call_node, + Node::Expr(hir::Expr { + kind: hir::ExprKind::MethodCall(_, receiver_expr, ..), + .. + }) + if receiver_expr.hir_id == *arg_hir_id + ); + if is_receiver { + err.multipart_suggestion_verbose( + msg, + vec![ + (span.shrink_to_lo(), format!("({derefs}")), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ) + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + msg, + derefs, + Applicability::MachineApplicable, + ) + }; + return true; } } else if let ( ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id: Some(rhs_hir_id), .. }, diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 565a2b8c573b4..5afa0a1975612 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -288,8 +288,6 @@ cfg_if::cfg_if! { } } -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint -#[allow(static_mut_refs)] pub unsafe fn panic(data: Box) -> u32 { use core::intrinsics::atomic_store_seqcst; diff --git a/library/std/src/os/emscripten/fs.rs b/library/std/src/os/emscripten/fs.rs index 3282b79ac1c81..81f9ef331a5fa 100644 --- a/library/std/src/os/emscripten/fs.rs +++ b/library/std/src/os/emscripten/fs.rs @@ -63,7 +63,7 @@ pub trait MetadataExt { impl MetadataExt for Metadata { #[allow(deprecated)] fn as_raw_stat(&self) -> &raw::stat { - unsafe { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) } + unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat) } } fn st_dev(&self) -> u64 { self.as_inner().as_inner().st_dev as u64 diff --git a/library/std/src/os/emscripten/raw.rs b/library/std/src/os/emscripten/raw.rs index d23011c738141..7ae8c45a6f80a 100644 --- a/library/std/src/os/emscripten/raw.rs +++ b/library/std/src/os/emscripten/raw.rs @@ -1,6 +1,4 @@ //! Emscripten-specific raw type definitions -//! This is basically exactly the same as the linux definitions, -//! except using the musl-specific stat64 structure in liblibc. #![stable(feature = "raw_ext", since = "1.1.0")] #![deprecated( diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 6a28799ca55eb..2fc33bdfefbf5 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -5,7 +5,6 @@ mod tests; #[cfg(not(any( target_os = "linux", - target_os = "emscripten", target_os = "l4re", target_os = "android", target_os = "hurd", @@ -14,7 +13,6 @@ use libc::off_t as off64_t; #[cfg(any( target_os = "android", target_os = "linux", - target_os = "emscripten", target_os = "l4re", target_os = "hurd", ))] diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 3307fa47c7f88..f7aa0b02f1278 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -8,16 +8,11 @@ mod tests; use libc::c_char; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "android", target_os = "hurd" ))] use libc::dirfd; -#[cfg(any( - all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", - target_os = "hurd" -))] +#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] use libc::fstatat64; #[cfg(any( target_os = "android", @@ -29,12 +24,12 @@ use libc::fstatat64; target_os = "nto", target_os = "vita", all(target_os = "linux", target_env = "musl"), + target_os = "emscripten", ))] use libc::readdir as readdir64; #[cfg(not(any( target_os = "android", target_os = "linux", - target_os = "emscripten", target_os = "solaris", target_os = "illumos", target_os = "l4re", @@ -48,7 +43,7 @@ use libc::readdir as readdir64; use libc::readdir_r as readdir64_r; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] use libc::readdir64; -#[cfg(any(target_os = "emscripten", target_os = "l4re"))] +#[cfg(target_os = "l4re")] use libc::readdir64_r; use libc::{c_int, mode_t}; #[cfg(target_os = "android")] @@ -58,7 +53,6 @@ use libc::{ }; #[cfg(not(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "l4re", target_os = "android", target_os = "hurd", @@ -69,7 +63,6 @@ use libc::{ }; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "l4re", target_os = "hurd" ))] @@ -899,7 +892,6 @@ impl DirEntry { #[cfg(all( any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "android", target_os = "hurd" ), @@ -928,7 +920,6 @@ impl DirEntry { #[cfg(any( not(any( all(target_os = "linux", not(target_env = "musl")), - target_os = "emscripten", target_os = "android", target_os = "hurd", )), diff --git a/src/doc/book b/src/doc/book index ad2011d3bcad9..04d06dfe54160 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ad2011d3bcad9f152d034faf7635c22506839d58 +Subproject commit 04d06dfe541607e6419f3d028c3f9b245f3be4d9 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index bc4ce51e1d4da..d56e0f3a0656b 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit bc4ce51e1d4dacb9350a92e95f6159a42de2f8c6 +Subproject commit d56e0f3a0656b7702ca466d4b191e16c28262b82 diff --git a/src/doc/nomicon b/src/doc/nomicon index 97e84a38c94bf..7ef05b9777c94 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 97e84a38c94bf9362b11284c20b2cb4adaa1e868 +Subproject commit 7ef05b9777c94836bc92f50f23e6e00981521a89 diff --git a/src/doc/reference b/src/doc/reference index 9f41bc11342d4..acd6794e712d5 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 9f41bc11342d46544ae0732caf14ec0bcaf27376 +Subproject commit acd6794e712d5e2ef6f5c84fb95688d32a69b816 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 76406337f4131..093397535b48a 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 76406337f4131253443aea0ed7e7f451b464117c +Subproject commit 093397535b48ae13ec76bc526b7e6eb8c096a85c diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 7f7ba48f04abc..ad93c5f1c49f2 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 7f7ba48f04abc2ad25e52f30b5e2bffa286b019f +Subproject commit ad93c5f1c49f2aeb45f7a4954017b1e607df9f5e diff --git a/tests/ui/borrowck/index-mut-help.stderr b/tests/ui/borrowck/index-mut-help.stderr index fde2b5dc07626..c4c9c1c531399 100644 --- a/tests/ui/borrowck/index-mut-help.stderr +++ b/tests/ui/borrowck/index-mut-help.stderr @@ -5,7 +5,10 @@ LL | map["peter"].clear(); | ^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` - = help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API +help: to modify a `HashMap<&str, String>` use `.get_mut()` + | +LL | if let Some(val) = map.get_mut("peter") { val.clear(); }; + | ++++++++++++++++++ ~~~~~~~~~ ~~~~~~~ +++ error[E0594]: cannot assign to data in an index of `HashMap<&str, String>` --> $DIR/index-mut-help.rs:11:5 @@ -14,12 +17,12 @@ LL | map["peter"] = "0".to_string(); | ^^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` -help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API +help: use `.insert()` to insert a value into a `HashMap<&str, String>`, `.get_mut()` to modify it, or the entry API for more flexibility | LL | map.insert("peter", "0".to_string()); | ~~~~~~~~ ~ + -LL | map.get_mut("peter").map(|val| { *val = "0".to_string(); }); - | ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++ +LL | if let Some(val) = map.get_mut("peter") { *val = "0".to_string(); }; + | ++++++++++++++++++ ~~~~~~~~~ ~~~~~~~~ +++ LL | let val = map.entry("peter").or_insert("0".to_string()); | +++++++++ ~~~~~~~ ~~~~~~~~~~~~ + diff --git a/tests/ui/btreemap/btreemap-index-mut-2.stderr b/tests/ui/btreemap/btreemap-index-mut-2.stderr index 0b8c77cb9e104..c42462ee1eb53 100644 --- a/tests/ui/btreemap/btreemap-index-mut-2.stderr +++ b/tests/ui/btreemap/btreemap-index-mut-2.stderr @@ -5,12 +5,12 @@ LL | map[&0] = 1; | ^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap` -help: to modify a `BTreeMap`, use `.get_mut()`, `.insert()` or the entry API +help: use `.insert()` to insert a value into a `BTreeMap`, `.get_mut()` to modify it, or the entry API for more flexibility | LL | map.insert(&0, 1); | ~~~~~~~~ ~ + -LL | map.get_mut(&0).map(|val| { *val = 1; }); - | ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++ +LL | if let Some(val) = map.get_mut(&0) { *val = 1; }; + | ++++++++++++++++++ ~~~~~~~~~ ~~~~~~~~ +++ LL | let val = map.entry(&0).or_insert(1); | +++++++++ ~~~~~~~ ~~~~~~~~~~~~ + diff --git a/tests/ui/btreemap/btreemap-index-mut.stderr b/tests/ui/btreemap/btreemap-index-mut.stderr index cc465fbf3def8..f402f503c1578 100644 --- a/tests/ui/btreemap/btreemap-index-mut.stderr +++ b/tests/ui/btreemap/btreemap-index-mut.stderr @@ -5,12 +5,12 @@ LL | map[&0] = 1; | ^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `BTreeMap` -help: to modify a `BTreeMap`, use `.get_mut()`, `.insert()` or the entry API +help: use `.insert()` to insert a value into a `BTreeMap`, `.get_mut()` to modify it, or the entry API for more flexibility | LL | map.insert(&0, 1); | ~~~~~~~~ ~ + -LL | map.get_mut(&0).map(|val| { *val = 1; }); - | ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++ +LL | if let Some(val) = map.get_mut(&0) { *val = 1; }; + | ++++++++++++++++++ ~~~~~~~~~ ~~~~~~~~ +++ LL | let val = map.entry(&0).or_insert(1); | +++++++++ ~~~~~~~ ~~~~~~~~~~~~ + diff --git a/tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed b/tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed new file mode 100644 index 0000000000000..a080a65854ab3 --- /dev/null +++ b/tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed @@ -0,0 +1,25 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/129966 +//! +//! Ensure we provide suggestion for wrongly ordered format parameters. + +//@ run-rustfix +#![allow(dead_code)] + +#[derive(Debug)] +struct Foo(u8, u8); + +fn main() { + let f = Foo(1, 2); + + println!("{f:#?}"); + //~^ ERROR invalid format string: expected `}`, found `#` + //~| HELP did you mean `#?`? + + println!("{f:x?}"); + //~^ ERROR invalid format string: expected `}`, found `x` + //~| HELP did you mean `x?`? + + println!("{f:X?}"); + //~^ ERROR invalid format string: expected `}`, found `X` + //~| HELP did you mean `X?`? +} diff --git a/tests/ui/fmt/suggest-wrongly-order-format-parameter.rs b/tests/ui/fmt/suggest-wrongly-order-format-parameter.rs new file mode 100644 index 0000000000000..830dafd447908 --- /dev/null +++ b/tests/ui/fmt/suggest-wrongly-order-format-parameter.rs @@ -0,0 +1,25 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/129966 +//! +//! Ensure we provide suggestion for wrongly ordered format parameters. + +//@ run-rustfix +#![allow(dead_code)] + +#[derive(Debug)] +struct Foo(u8, u8); + +fn main() { + let f = Foo(1, 2); + + println!("{f:?#}"); + //~^ ERROR invalid format string: expected `}`, found `#` + //~| HELP did you mean `#?`? + + println!("{f:?x}"); + //~^ ERROR invalid format string: expected `}`, found `x` + //~| HELP did you mean `x?`? + + println!("{f:?X}"); + //~^ ERROR invalid format string: expected `}`, found `X` + //~| HELP did you mean `X?`? +} diff --git a/tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr b/tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr new file mode 100644 index 0000000000000..fe693d2e90410 --- /dev/null +++ b/tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr @@ -0,0 +1,35 @@ +error: invalid format string: expected `}`, found `#` + --> $DIR/suggest-wrongly-order-format-parameter.rs:14:19 + | +LL | println!("{f:?#}"); + | ^ expected `'}'` in format string + | +help: did you mean `#?`? + | +LL | println!("{f:#?}"); + | ~~ + +error: invalid format string: expected `}`, found `x` + --> $DIR/suggest-wrongly-order-format-parameter.rs:18:19 + | +LL | println!("{f:?x}"); + | ^ expected `'}'` in format string + | +help: did you mean `x?`? + | +LL | println!("{f:x?}"); + | ~~ + +error: invalid format string: expected `}`, found `X` + --> $DIR/suggest-wrongly-order-format-parameter.rs:22:19 + | +LL | println!("{f:?X}"); + | ^ expected `'}'` in format string + | +help: did you mean `X?`? + | +LL | println!("{f:X?}"); + | ~~ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/hashmap/hashmap-index-mut.stderr b/tests/ui/hashmap/hashmap-index-mut.stderr index 2381b8ecb9692..ad33c6f9b1540 100644 --- a/tests/ui/hashmap/hashmap-index-mut.stderr +++ b/tests/ui/hashmap/hashmap-index-mut.stderr @@ -5,12 +5,12 @@ LL | map[&0] = 1; | ^^^^^^^^^^^ cannot assign | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap` -help: to modify a `HashMap`, use `.get_mut()`, `.insert()` or the entry API +help: use `.insert()` to insert a value into a `HashMap`, `.get_mut()` to modify it, or the entry API for more flexibility | LL | map.insert(&0, 1); | ~~~~~~~~ ~ + -LL | map.get_mut(&0).map(|val| { *val = 1; }); - | ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++ +LL | if let Some(val) = map.get_mut(&0) { *val = 1; }; + | ++++++++++++++++++ ~~~~~~~~~ ~~~~~~~~ +++ LL | let val = map.entry(&0).or_insert(1); | +++++++++ ~~~~~~~ ~~~~~~~~~~~~ + diff --git a/tests/ui/issues/issue-41726.stderr b/tests/ui/issues/issue-41726.stderr index fe7d4df70676f..250bba222bfdb 100644 --- a/tests/ui/issues/issue-41726.stderr +++ b/tests/ui/issues/issue-41726.stderr @@ -5,7 +5,10 @@ LL | things[src.as_str()].sort(); | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap>` - = help: to modify a `HashMap>`, use `.get_mut()`, `.insert()` or the entry API +help: to modify a `HashMap>` use `.get_mut()` + | +LL | if let Some(val) = things.get_mut(src.as_str()) { val.sort(); }; + | ++++++++++++++++++ ~~~~~~~~~ ~~~~~~~ +++ error: aborting due to 1 previous error diff --git a/tests/ui/no_send-rc.stderr b/tests/ui/no_send-rc.stderr index 3534167870baf..1430a7a29ea26 100644 --- a/tests/ui/no_send-rc.stderr +++ b/tests/ui/no_send-rc.stderr @@ -12,6 +12,10 @@ note: required by a bound in `bar` | LL | fn bar(_: T) {} | ^^^^ required by this bound in `bar` +help: consider dereferencing here + | +LL | bar(*x); + | + error: aborting due to 1 previous error diff --git a/tests/ui/structs/manual-default-impl-could-be-derived.stderr b/tests/ui/structs/manual-default-impl-could-be-derived.stderr index e8f607fac7edd..cf06d5418e12c 100644 --- a/tests/ui/structs/manual-default-impl-could-be-derived.stderr +++ b/tests/ui/structs/manual-default-impl-could-be-derived.stderr @@ -31,7 +31,10 @@ LL | | y: 0, LL | | } | |_^ | - = help: to avoid divergence in behavior between `Struct { .. }` and `::default()`, derive the `Default` +help: to avoid divergence in behavior between `Struct { .. }` and `::default()`, derive the `Default` + | +LL ~ #[derive(Default)] struct B { + | error: `Default` impl doesn't use the declared default field values --> $DIR/manual-default-impl-could-be-derived.rs:43:1 diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr index a6324a824c1c3..3db400418c711 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.stderr +++ b/tests/ui/suggestions/issue-84973-blacklist.stderr @@ -86,6 +86,10 @@ note: required by a bound in `f_send` | LL | fn f_send(t: T) {} | ^^^^ required by this bound in `f_send` +help: consider dereferencing here + | +LL | f_send(*rc); + | + error: aborting due to 5 previous errors diff --git a/tests/ui/traits/suggest-dereferences/deref-argument.fixed b/tests/ui/traits/suggest-dereferences/deref-argument.fixed new file mode 100644 index 0000000000000..8235ae0b62840 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/deref-argument.fixed @@ -0,0 +1,37 @@ +//@ run-rustfix +//! diagnostic test for #90997. +//! test that E0277 suggests dereferences to satisfy bounds when the referent is `Copy` or boxed. +use std::ops::Deref; + +trait Test { + fn test(self); +} +fn consume_test(x: impl Test) { x.test() } + +impl Test for u32 { + fn test(self) {} +} +struct MyRef(u32); +impl Deref for MyRef { + type Target = u32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +struct NonCopy; +impl Test for NonCopy { + fn test(self) {} +} + +fn main() { + let my_ref = MyRef(0); + consume_test(*my_ref); + //~^ ERROR the trait bound `MyRef: Test` is not satisfied + //~| SUGGESTION * + + let nested_box = Box::new(Box::new(Box::new(NonCopy))); + consume_test(***nested_box); + //~^ ERROR the trait bound `Box>>: Test` is not satisfied + //~| SUGGESTION *** +} diff --git a/tests/ui/traits/suggest-dereferences/deref-argument.rs b/tests/ui/traits/suggest-dereferences/deref-argument.rs new file mode 100644 index 0000000000000..2f96b75c4e476 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/deref-argument.rs @@ -0,0 +1,37 @@ +//@ run-rustfix +//! diagnostic test for #90997. +//! test that E0277 suggests dereferences to satisfy bounds when the referent is `Copy` or boxed. +use std::ops::Deref; + +trait Test { + fn test(self); +} +fn consume_test(x: impl Test) { x.test() } + +impl Test for u32 { + fn test(self) {} +} +struct MyRef(u32); +impl Deref for MyRef { + type Target = u32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +struct NonCopy; +impl Test for NonCopy { + fn test(self) {} +} + +fn main() { + let my_ref = MyRef(0); + consume_test(my_ref); + //~^ ERROR the trait bound `MyRef: Test` is not satisfied + //~| SUGGESTION * + + let nested_box = Box::new(Box::new(Box::new(NonCopy))); + consume_test(nested_box); + //~^ ERROR the trait bound `Box>>: Test` is not satisfied + //~| SUGGESTION *** +} diff --git a/tests/ui/traits/suggest-dereferences/deref-argument.stderr b/tests/ui/traits/suggest-dereferences/deref-argument.stderr new file mode 100644 index 0000000000000..3dc92fd6ab6f8 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/deref-argument.stderr @@ -0,0 +1,39 @@ +error[E0277]: the trait bound `MyRef: Test` is not satisfied + --> $DIR/deref-argument.rs:29:18 + | +LL | consume_test(my_ref); + | ------------ ^^^^^^ the trait `Test` is not implemented for `MyRef` + | | + | required by a bound introduced by this call + | +note: required by a bound in `consume_test` + --> $DIR/deref-argument.rs:9:25 + | +LL | fn consume_test(x: impl Test) { x.test() } + | ^^^^ required by this bound in `consume_test` +help: consider dereferencing here + | +LL | consume_test(*my_ref); + | + + +error[E0277]: the trait bound `Box>>: Test` is not satisfied + --> $DIR/deref-argument.rs:34:18 + | +LL | consume_test(nested_box); + | ------------ ^^^^^^^^^^ the trait `Test` is not implemented for `Box>>` + | | + | required by a bound introduced by this call + | +note: required by a bound in `consume_test` + --> $DIR/deref-argument.rs:9:25 + | +LL | fn consume_test(x: impl Test) { x.test() } + | ^^^^ required by this bound in `consume_test` +help: consider dereferencing here + | +LL | consume_test(***nested_box); + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.