From b96d1e45f188010f2cc6fff956902a455eb2178a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 17:06:29 -0400 Subject: [PATCH 01/60] change ptr::swap methods to do untyped copies --- library/core/src/ptr/mod.rs | 24 ++++++++++++------------ library/core/tests/ptr.rs | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 5b04ae7b07e69..3b2b7ba8531ca 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -905,15 +905,15 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { if mem::align_of::() >= mem::align_of::<$ChunkTy>() && mem::size_of::() % mem::size_of::<$ChunkTy>() == 0 { - let x: *mut MaybeUninit<$ChunkTy> = x.cast(); - let y: *mut MaybeUninit<$ChunkTy> = y.cast(); + let x: *mut $ChunkTy = x.cast(); + let y: *mut $ChunkTy = y.cast(); let count = count * (mem::size_of::() / mem::size_of::<$ChunkTy>()); // SAFETY: these are the same bytes that the caller promised were // ok, just typed as `MaybeUninit`s instead of as `T`s. // The `if` condition above ensures that we're not violating // alignment requirements, and that the division is exact so // that we don't lose any bytes off the end. - return unsafe { swap_nonoverlapping_simple(x, y, count) }; + return unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }; } }; } @@ -946,7 +946,7 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { } // SAFETY: Same preconditions as this function - unsafe { swap_nonoverlapping_simple(x, y, count) } + unsafe { swap_nonoverlapping_simple_untyped(x, y, count) } } /// Same behaviour and safety conditions as [`swap_nonoverlapping`] @@ -955,16 +955,16 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. #[inline] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] -const unsafe fn swap_nonoverlapping_simple(x: *mut T, y: *mut T, count: usize) { +const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, count: usize) { + let x = x.cast::>(); + let y = y.cast::>(); let mut i = 0; while i < count { - let x: &mut T = - // SAFETY: By precondition, `i` is in-bounds because it's below `n` - unsafe { &mut *x.add(i) }; - let y: &mut T = - // SAFETY: By precondition, `i` is in-bounds because it's below `n` - // and it's distinct from `x` since the ranges are non-overlapping - unsafe { &mut *y.add(i) }; + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + let x = unsafe { &mut *x.add(i) }; + // SAFETY: By precondition, `i` is in-bounds because it's below `n` + // and it's distinct from `x` since the ranges are non-overlapping + let y = unsafe { &mut *y.add(i) }; mem::swap_simple(x, y); i += 1; diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 40b2b49bdbd7d..082d438128e20 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -783,6 +783,31 @@ fn nonnull_tagged_pointer_with_provenance() { } } +#[test] +fn swap_copy_untyped() { + // We call `{swap,copy}{,_nonoverlapping}` at `bool` type on data that is not a valid bool. + // These should all do untyped copies, so this should work fine. + let mut x = 5u8; + let mut y = 6u8; + + let ptr1 = &mut x as *mut u8 as *mut bool; + let ptr2 = &mut y as *mut u8 as *mut bool; + + unsafe { + ptr::swap(ptr1, ptr2); + ptr::swap_nonoverlapping(ptr1, ptr2, 1); + } + assert_eq!(x, 5); + assert_eq!(y, 6); + + unsafe { + ptr::copy(ptr1, ptr2, 1); + ptr::copy_nonoverlapping(ptr1, ptr2, 1); + } + assert_eq!(x, 5); + assert_eq!(y, 5); +} + #[test] fn test_const_copy() { const { From cb7cd97641b7a2d1646520b7bf785934f9c6aaeb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 17:10:12 -0400 Subject: [PATCH 02/60] promise that ptr::copy and ptr::swap are doing untyped copies --- library/core/src/intrinsics.rs | 6 ++++++ library/core/src/ptr/mod.rs | 10 ++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 0b76790c0097e..9bed758c10a1d 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2043,6 +2043,9 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but /// with the argument order swapped. /// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy /// /// # Safety @@ -2148,6 +2151,9 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// order swapped. Copying takes place as if the bytes were copied from `src` /// to a temporary array and then copied from the array to `dst`. /// +/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove /// /// # Safety diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 3b2b7ba8531ca..1035fdbf12dd5 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -774,7 +774,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// Swaps the values at two mutable locations of the same type, without /// deinitializing either. /// -/// But for the following two exceptions, this function is semantically +/// But for the following exceptions, this function is semantically /// equivalent to [`mem::swap`]: /// /// * It operates on raw pointers instead of references. When references are @@ -784,6 +784,9 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// overlapping region of memory from `x` will be used. This is demonstrated /// in the second example below. /// +/// * The operation is "untyped" in the sense that data may be uninitialized or otherwise violate +/// the requirements of `T`. The initialization state is preserved exactly. +/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -860,6 +863,9 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { /// Swaps `count * size_of::()` bytes between the two regions of memory /// beginning at `x` and `y`. The two regions must *not* overlap. /// +/// The operation is "untyped" in the sense that data may be uninitialized or otherwise violate the +/// requirements of `T`. The initialization state is preserved exactly. +/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -965,7 +971,7 @@ const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, coun // SAFETY: By precondition, `i` is in-bounds because it's below `n` // and it's distinct from `x` since the ranges are non-overlapping let y = unsafe { &mut *y.add(i) }; - mem::swap_simple(x, y); + mem::swap_simple::>(x, y); i += 1; } From 7d2eba6311dfaf615866442fb9e3730a8d888748 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 11:38:45 +0100 Subject: [PATCH 03/60] middle: translation in `LintDiagnosticBuilder` Accept `DiagnosticMessage` in `LintDiagnosticBuilder::build` so that lints can be built with translatable diagnostic messages. Signed-off-by: David Wood --- compiler/rustc_errors/src/diagnostic_builder.rs | 2 +- compiler/rustc_lint/src/levels.rs | 4 ++-- compiler/rustc_middle/src/lint.rs | 5 +++-- compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 9e0a99849a3f4..1ad33ef25b763 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -529,7 +529,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { applicability: Applicability, ) -> &mut Self); - forward!(pub fn set_primary_message(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn set_primary_message(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn set_span(&mut self, sp: impl Into) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); forward!(pub fn set_arg( diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 4773feded12fa..bf4a726b06188 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -521,7 +521,7 @@ impl<'s> LintLevelsBuilder<'s> { src, Some(sp.into()), |lint| { - let mut err = lint.build(&msg); + let mut err = lint.build(msg); if let Some(new_name) = &renamed { err.span_suggestion( sp, @@ -548,7 +548,7 @@ impl<'s> LintLevelsBuilder<'s> { } else { name.to_string() }; - let mut db = lint.build(&format!("unknown lint: `{}`", name)); + let mut db = lint.build(format!("unknown lint: `{}`", name)); if let Some(suggestion) = suggestion { db.span_suggestion( sp, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 215d8decf2a88..32c0a7e260569 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -3,7 +3,8 @@ use std::cmp; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{ - Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed, MultiSpan, + Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee, + ErrorGuaranteed, MultiSpan, }; use rustc_hir::HirId; use rustc_index::vec::IndexVec; @@ -231,7 +232,7 @@ pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> { /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`. - pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a, G> { + pub fn build(mut self, msg: impl Into) -> DiagnosticBuilder<'a, G> { self.0.set_primary_message(msg); self.0.set_is_lint(); self.0 diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 845be2ab264a6..f22f3f61a01f2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -550,7 +550,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { id, span, |lint| { - lint.build(&msg).emit(); + lint.build(msg).emit(); }, ); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 40545b19b24dc..8c123c052e5ac 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1163,7 +1163,7 @@ impl CheckAttrVisitor<'_> { hir_id, meta.span(), |lint| { - lint.build(&"invalid `doc` attribute").emit(); + lint.build("invalid `doc` attribute").emit(); }, ); is_valid = false; From 0f4c4c5e1842f63ab869d75ea8c891078a64ca55 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 13:35:31 +0100 Subject: [PATCH 04/60] lint: port array-into-iter diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 6 ++++++ compiler/rustc_error_messages/src/lib.rs | 5 +++-- compiler/rustc_lint/src/array_into_iter.rs | 21 +++++++++---------- 3 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/lint.ftl diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl new file mode 100644 index 0000000000000..06c8f217c13af --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -0,0 +1,6 @@ +lint-array-into-iter = + this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021 + .use-iter-suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity + .remove-into-iter-suggestion = or remove `.into_iter()` to iterate by value + .use-explicit-into-iter-suggestion = + or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index d52b94b78dfac..563d0534d8f38 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -31,11 +31,12 @@ pub use unic_langid::{langid, LanguageIdentifier}; // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. fluent_messages! { + borrowck => "../locales/en-US/borrowck.ftl", + builtin_macros => "../locales/en-US/builtin_macros.ftl", + lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", privacy => "../locales/en-US/privacy.ftl", typeck => "../locales/en-US/typeck.ftl", - builtin_macros => "../locales/en-US/builtin_macros.ftl", - borrowck => "../locales/en-US/borrowck.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index b33ab40eb39cb..121fefdc6207a 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -1,5 +1,5 @@ use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; @@ -120,31 +120,30 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { _ => bug!("array type coerced to something other than array or slice"), }; cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| { - let mut diag = lint.build(&format!( - "this method call resolves to `<&{} as IntoIterator>::into_iter` \ - (due to backwards compatibility), \ - but will resolve to <{} as IntoIterator>::into_iter in Rust 2021", - target, target, - )); + let mut diag = lint.build(fluent::lint::array_into_iter); + diag.set_arg("target", target); diag.span_suggestion( call.ident.span, - "use `.iter()` instead of `.into_iter()` to avoid ambiguity", + fluent::lint::use_iter_suggestion, "iter", Applicability::MachineApplicable, ); if self.for_expr_span == expr.span { diag.span_suggestion( receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), - "or remove `.into_iter()` to iterate by value", + fluent::lint::remove_into_iter_suggestion, "", Applicability::MaybeIncorrect, ); } else if receiver_ty.is_array() { diag.multipart_suggestion( - "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value", + fluent::lint::use_explicit_into_iter_suggestion, vec![ (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()), - (receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()), + ( + receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + ")".into(), + ), ], Applicability::MaybeIncorrect, ); From 2a69640eb2a8086ed848808efaf79c99781a78e5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 14:08:02 +0100 Subject: [PATCH 05/60] lint: port enum intrinsics diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 8 +++++ .../src/enum_intrinsics_non_enums.rs | 30 +++++-------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 06c8f217c13af..2ad077514c853 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -4,3 +4,11 @@ lint-array-into-iter = .remove-into-iter-suggestion = or remove `.into_iter()` to iterate by value .use-explicit-into-iter-suggestion = or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + +lint-enum-intrinsics-mem-discriminant = + the return value of `mem::discriminant` is unspecified when called with a non-enum type + .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. + +lint-enum-intrinsics-mem-variant = + the return value of `mem::variant_count` is unspecified when called with a non-enum type + .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index c5e15a88fdf1c..5d212768d0d8b 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -1,4 +1,5 @@ use crate::{context::LintContext, LateContext, LateLintPass}; +use rustc_errors::fluent; use rustc_hir as hir; use rustc_middle::ty::{fold::TypeFoldable, Ty}; use rustc_span::{symbol::sym, Span}; @@ -51,19 +52,9 @@ fn enforce_mem_discriminant( if is_non_enum(ty_param) { cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| { builder - .build( - "the return value of `mem::discriminant` is \ - unspecified when called with a non-enum type", - ) - .span_note( - args_span, - &format!( - "the argument to `discriminant` should be a \ - reference to an enum, but it was passed \ - a reference to a `{}`, which is not an enum.", - ty_param, - ), - ) + .build(fluent::lint::enum_intrinsics_mem_discriminant) + .set_arg("ty_param", ty_param) + .span_note(args_span, fluent::lint::note) .emit(); }); } @@ -74,16 +65,9 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp if is_non_enum(ty_param) { cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| { builder - .build( - "the return value of `mem::variant_count` is \ - unspecified when called with a non-enum type", - ) - .note(&format!( - "the type parameter of `variant_count` should \ - be an enum, but it was instantiated with \ - the type `{}`, which is not an enum.", - ty_param, - )) + .build(fluent::lint::enum_intrinsics_mem_variant) + .set_arg("ty_param", ty_param) + .note(fluent::lint::note) .emit(); }); } From a0624eb6c9236323eda00379a8342fba0af2e78d Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 14:15:31 +0100 Subject: [PATCH 06/60] lint: port expectation diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/expect.rs | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 2ad077514c853..a29c2208ebabf 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -12,3 +12,6 @@ lint-enum-intrinsics-mem-discriminant = lint-enum-intrinsics-mem-variant = the return value of `mem::variant_count` is unspecified when called with a non-enum type .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. + +lint-expectation = this lint expectation is unfulfilled + .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 95e3125045db4..699e81543188f 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,4 +1,5 @@ use crate::builtin; +use rustc_errors::fluent; use rustc_hir::HirId; use rustc_middle::ty::query::Providers; use rustc_middle::{lint::LintExpectation, ty::TyCtxt}; @@ -43,13 +44,13 @@ fn emit_unfulfilled_expectation_lint( hir_id, expectation.emission_span, |diag| { - let mut diag = diag.build("this lint expectation is unfulfilled"); + let mut diag = diag.build(fluent::lint::expectation); if let Some(rationale) = expectation.reason { diag.note(rationale.as_str()); } if expectation.is_unfulfilled_lint_expectations { - diag.note("the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message"); + diag.note(fluent::lint::note); } diag.emit(); From fd57269e8c355e54f61d1e19078a2f9586e48c43 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 14:40:55 +0100 Subject: [PATCH 07/60] lint: port hidden unicode codepoints diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 13 ++++++ .../src/hidden_unicode_codepoints.rs | 44 ++++++------------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index a29c2208ebabf..474f902bff6d5 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -15,3 +15,16 @@ lint-enum-intrinsics-mem-variant = lint-expectation = this lint expectation is unfulfilled .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + +lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of text present in {$label} + .label = this {$label} contains {$count -> + [one] an invisible + *[other] invisible + } unicode text flow control {$count -> + [one] codepoint + *[other] codepoints + } + .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + .suggestion-remove = if their presence wasn't intentional, you can remove them + .suggestion-escape = if you want to keep them but make them visible in your source code, you can escape them + .no-suggestion-note-escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index fc99d759a03f5..fe2712525eea5 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -1,7 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS}; use rustc_ast as ast; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::{fluent, Applicability, SuggestionStyle}; use rustc_span::{BytePos, Span, Symbol}; declare_lint! { @@ -61,41 +61,25 @@ impl HiddenUnicodeCodepoints { .collect(); cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| { - let mut err = lint.build(&format!( - "unicode codepoint changing visible direction of text present in {}", - label - )); - let (an, s) = match spans.len() { - 1 => ("an ", ""), - _ => ("", "s"), - }; - err.span_label( - span, - &format!( - "this {} contains {}invisible unicode text flow control codepoint{}", - label, an, s, - ), - ); + let mut err = lint.build(fluent::lint::hidden_unicode_codepoints); + err.set_arg("label", label); + err.set_arg("count", spans.len()); + err.span_label(span, fluent::lint::label); + err.note(fluent::lint::note); if point_at_inner_spans { for (c, span) in &spans { err.span_label(*span, format!("{:?}", c)); } } - err.note( - "these kind of unicode codepoints change the way text flows on applications that \ - support them, but can cause confusion because they change the order of \ - characters on the screen", - ); if point_at_inner_spans && !spans.is_empty() { err.multipart_suggestion_with_style( - "if their presence wasn't intentional, you can remove them", + fluent::lint::suggestion_remove, spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); err.multipart_suggestion( - "if you want to keep them but make them visible in your source code, you can \ - escape them", + fluent::lint::suggestion_escape, spans .into_iter() .map(|(c, span)| { @@ -109,16 +93,16 @@ impl HiddenUnicodeCodepoints { // FIXME: in other suggestions we've reversed the inner spans of doc comments. We // should do the same here to provide the same good suggestions as we do for // literals above. - err.note("if their presence wasn't intentional, you can remove them"); - err.note(&format!( - "if you want to keep them but make them visible in your source code, you can \ - escape them: {}", + err.set_arg( + "escaped", spans .into_iter() - .map(|(c, _)| { format!("{:?}", c) }) + .map(|(c, _)| format!("{:?}", c)) .collect::>() .join(", "), - )); + ); + err.note(fluent::lint::suggestion_remove); + err.note(fluent::lint::no_suggestion_note_escape); } err.emit(); }); From e88916cc926da547f68ae24e44f11a1a1fa5d34d Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 14:46:45 +0100 Subject: [PATCH 08/60] lint: port default hash types diagnostics Signed-off-by: David Wood --- .../rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/internal.rs | 13 +++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 474f902bff6d5..ff6feb4686891 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -28,3 +28,6 @@ lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of .suggestion-remove = if their presence wasn't intentional, you can remove them .suggestion-escape = if you want to keep them but make them visible in your source code, you can escape them .no-suggestion-note-escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} + +lint-default-hash-types = prefer `{$preferred}` over `{$used}`, it has better performance + .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 56c8635a189e1..24e58bbcb00e6 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir::def::Res; use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; @@ -36,13 +36,10 @@ impl LateLintPass<'_> for DefaultHashTypes { _ => return, }; cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| { - let msg = format!( - "prefer `{}` over `{}`, it has better performance", - replace, - cx.tcx.item_name(def_id) - ); - lint.build(&msg) - .note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace)) + lint.build(fluent::lint::default_hash_types) + .set_arg("preferred", replace) + .set_arg("used", cx.tcx.item_name(def_id)) + .note(fluent::lint::note) .emit(); }); } From 81395425985edee9260fdf597d3dcf0f67ada4bb Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 14:50:58 +0100 Subject: [PATCH 09/60] lint: port query instability diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/internal.rs | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index ff6feb4686891..5b793ed93e8a0 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -31,3 +31,6 @@ lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of lint-default-hash-types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary + +lint-query-instability = using `{$query}` can result in unstable query results + .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 24e58bbcb00e6..90274503274aa 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -96,12 +96,9 @@ impl LateLintPass<'_> for QueryStability { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| { - let msg = format!( - "using `{}` can result in unstable query results", - cx.tcx.item_name(def_id) - ); - lint.build(&msg) - .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale") + lint.build(fluent::lint::query_instability) + .set_arg("query", cx.tcx.item_name(def_id)) + .note(fluent::lint::note) .emit(); }) } From 0996a7ab5cecaf8c962e4df2450edd8371d1d93f Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 15:00:01 +0100 Subject: [PATCH 10/60] lint: port ty diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 9 ++++++++ compiler/rustc_lint/src/internal.rs | 23 ++++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 5b793ed93e8a0..43c21b380a5f4 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -34,3 +34,12 @@ lint-default-hash-types = prefer `{$preferred}` over `{$used}`, it has better pe lint-query-instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +lint-tykind-kind = usage of `ty::TyKind::` + .suggestion = try using `ty::` directly + +lint-tykind = usage of `ty::TyKind` + .help = try using `Ty` instead + +lint-ty-qualified = usage of qualified `ty::{$ty}` + .suggestion = try importing it and using it unqualified diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 90274503274aa..3707abd2838be 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -140,10 +140,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() ); cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { - lint.build("usage of `ty::TyKind::`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( span, - "try using `ty::` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -169,10 +169,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { - lint.build("usage of `ty::TyKind::`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( path.span, - "try using `ty::` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -187,10 +187,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { - lint.build("usage of `ty::TyKind::`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( path.span, - "try using `ty::` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -207,10 +207,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { - lint.build("usage of `ty::TyKind::`") + lint.build(fluent::lint::tykind_kind) .span_suggestion( path.span, - "try using `ty::` directly", + fluent::lint::suggestion, "ty", Applicability::MaybeIncorrect, // ty maybe needs an import ) @@ -220,15 +220,16 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } _ => {} } - lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit(); + lint.build(fluent::lint::tykind).help(fluent::lint::help).emit(); }) } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) { if path.segments.len() > 1 { cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| { - lint.build(&format!("usage of qualified `ty::{}`", t)) + lint.build(fluent::lint::ty_qualified) + .set_arg("ty", t.clone()) .span_suggestion( path.span, - "try importing it and using it unqualified", + fluent::lint::suggestion, t, // The import probably needs to be changed Applicability::MaybeIncorrect, From 1c3a3e07114d651b41cb050d8e6cbff8b8528295 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 15:09:24 +0100 Subject: [PATCH 11/60] lint: port impl `LintPass` by hand diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/internal.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 43c21b380a5f4..ec0b9697a746d 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -43,3 +43,6 @@ lint-tykind = usage of `ty::TyKind` lint-ty-qualified = usage of qualified `ty::{$ty}` .suggestion = try importing it and using it unqualified + +lint-lintpass-by-hand = implementing `LintPass` by hand + .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 3707abd2838be..92273360d2e5e 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -325,8 +325,8 @@ impl EarlyLintPass for LintPassImpl { LINT_PASS_IMPL_WITHOUT_MACRO, lint_pass.path.span, |lint| { - lint.build("implementing `LintPass` by hand") - .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") + lint.build(fluent::lint::lintpass_by_hand) + .help(fluent::lint::help) .emit(); }, ) From 674ac60d5aad1a1e389042a0658b5b805c2c3c7a Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 15:18:30 +0100 Subject: [PATCH 12/60] lint: port non-existant doc keyword diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/internal.rs | 11 ++++------- .../internal-lints/existing_doc_keyword.stderr | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index ec0b9697a746d..5a14bec4db6af 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -46,3 +46,6 @@ lint-ty-qualified = usage of qualified `ty::{$ty}` lint-lintpass-by-hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead + +lint-non-existant-doc-keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]` + .help = only existing keywords are allowed in core/std diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 92273360d2e5e..817c30f7f7e2e 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -366,13 +366,10 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { return; } cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { - lint.build(&format!( - "Found non-existing keyword `{}` used in \ - `#[doc(keyword = \"...\")]`", - v, - )) - .help("only existing keywords are allowed in core/std") - .emit(); + lint.build(fluent::lint::non_existant_doc_keyword) + .set_arg("keyword", v) + .help(fluent::lint::help) + .emit(); }); } } diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr index bac44f338b74c..bc9fcdd7bc7a5 100644 --- a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr +++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr @@ -1,4 +1,4 @@ -error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]` +error: found non-existing keyword `tadam` used in `#[doc(keyword = \"...\")]` --> $DIR/existing_doc_keyword.rs:10:1 | LL | #[doc(keyword = "tadam")] From 4f35c7993b7b9a0301b0af27aa78a637fce4208b Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 15:27:41 +0100 Subject: [PATCH 13/60] lint: port translation migration diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 5 +++++ compiler/rustc_lint/src/internal.rs | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 5a14bec4db6af..7c717a724e009 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -49,3 +49,8 @@ lint-lintpass-by-hand = implementing `LintPass` by hand lint-non-existant-doc-keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]` .help = only existing keywords are allowed in core/std + +lint-diag-out-of-impl = + diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls + +lint-untranslatable-diag = diagnostics should be created using translatable messages diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 817c30f7f7e2e..5bcf9390c076a 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -423,8 +423,7 @@ impl LateLintPass<'_> for Diagnostics { debug!(?found_impl); if !found_impl { cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| { - lint.build("diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls") - .emit(); + lint.build(fluent::lint::diag_out_of_impl).emit(); }) } @@ -442,7 +441,7 @@ impl LateLintPass<'_> for Diagnostics { debug!(?found_diagnostic_message); if !found_diagnostic_message { cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| { - lint.build("diagnostics should be created using translatable messages").emit(); + lint.build(fluent::lint::untranslatable_diag).emit(); }) } } From c29e05e7450053e2a90635976a7fe2d6e5a7fd15 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 15:47:27 +0100 Subject: [PATCH 14/60] lint: port `CString` ptr diagnostics Signed-off-by: David Wood --- .../rustc_error_messages/locales/en-US/lint.ftl | 6 ++++++ compiler/rustc_lint/src/methods.rs | 17 +++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 7c717a724e009..178a58f1836ba 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -54,3 +54,9 @@ lint-diag-out-of-impl = diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls lint-untranslatable-diag = diagnostics should be created using translatable messages + +lint-cstring-ptr = getting the inner pointer of a temporary `CString` + .as-ptr-label = this pointer will be invalid + .unwrap-label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + .help = for more information, see https://doc.rust-lang.org/reference/destructors.html diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index b6a45676a3093..ff5a01749c19e 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -1,6 +1,7 @@ use crate::LateContext; use crate::LateLintPass; use crate::LintContext; +use rustc_errors::fluent; use rustc_hir::{Expr, ExprKind, PathSegment}; use rustc_middle::ty; use rustc_span::{symbol::sym, ExpnKind, Span}; @@ -88,16 +89,12 @@ fn lint_cstring_as_ptr( if let ty::Adt(adt, _) = substs.type_at(0).kind() { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| { - let mut diag = diag - .build("getting the inner pointer of a temporary `CString`"); - diag.span_label(as_ptr_span, "this pointer will be invalid"); - diag.span_label( - unwrap.span, - "this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime", - ); - diag.note("pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned"); - diag.help("for more information, see https://doc.rust-lang.org/reference/destructors.html"); - diag.emit(); + diag.build(fluent::lint::cstring_ptr) + .span_label(as_ptr_span, fluent::lint::as_ptr_label) + .span_label(unwrap.span, fluent::lint::unwrap_label) + .note(fluent::lint::note) + .help(fluent::lint::help) + .emit(); }); } } From 48e4bf115f2c4a4ac051f49dab862610fe57f622 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 15:57:35 +0100 Subject: [PATCH 15/60] lint: port non-ascii-idents diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 12 +++++++ compiler/rustc_lint/src/non_ascii_idents.rs | 35 +++++++++---------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 178a58f1836ba..34445c3940a23 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -60,3 +60,15 @@ lint-cstring-ptr = getting the inner pointer of a temporary `CString` .unwrap-label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned .help = for more information, see https://doc.rust-lang.org/reference/destructors.html + +lint-identifier-non-ascii-char = identifier contains non-ASCII characters + +lint-identifier-uncommon-codepoints = identifier contains uncommon Unicode codepoints + +lint-confusable-identifier-pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` + .label = this is where the previous identifier occurred + +lint-mixed-script-confusables = + the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables + .includes-note = the usage includes {$includes} + .note = please recheck to make sure their usages are indeed what you want diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 6182d2b10ed5b..764003e61a6df 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -1,6 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::fluent; use rustc_span::symbol::Symbol; declare_lint! { @@ -180,13 +181,13 @@ impl EarlyLintPass for NonAsciiIdents { } has_non_ascii_idents = true; cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| { - lint.build("identifier contains non-ASCII characters").emit(); + lint.build(fluent::lint::identifier_non_ascii_char).emit(); }); if check_uncommon_codepoints && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) { cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| { - lint.build("identifier contains uncommon Unicode codepoints").emit(); + lint.build(fluent::lint::identifier_uncommon_codepoints).emit(); }) } } @@ -216,15 +217,11 @@ impl EarlyLintPass for NonAsciiIdents { .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| { if !*existing_is_ascii || !is_ascii { cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| { - lint.build(&format!( - "identifier pair considered confusable between `{}` and `{}`", - existing_symbol, symbol - )) - .span_label( - *existing_span, - "this is where the previous identifier occurred", - ) - .emit(); + lint.build(fluent::lint::confusable_identifier_pair) + .set_arg("existing_sym", *existing_symbol) + .set_arg("sym", symbol) + .span_label(*existing_span, fluent::lint::label) + .emit(); }); } if *existing_is_ascii && !is_ascii { @@ -326,18 +323,20 @@ impl EarlyLintPass for NonAsciiIdents { for ((sp, ch_list), script_set) in lint_reports { cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| { - let message = format!( - "the usage of Script Group `{}` in this crate consists solely of mixed script confusables", - script_set); - let mut note = "the usage includes ".to_string(); + let mut includes = String::new(); for (idx, ch) in ch_list.into_iter().enumerate() { if idx != 0 { - note += ", "; + includes += ", "; } let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); - note += &char_info; + includes += &char_info; } - lint.build(&message).note(¬e).note("please recheck to make sure their usages are indeed what you want").emit(); + lint.build(fluent::lint::mixed_script_confusables) + .set_arg("set", script_set.to_string()) + .set_arg("includes", includes) + .note(fluent::lint::includes_note) + .note(fluent::lint::note) + .emit(); }); } } From 7ee4aa700321d0dc2a763a324fd1c0828d73f70f Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 16:33:57 +0100 Subject: [PATCH 16/60] lint: port non-fmt-panic diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 36 +++++++ compiler/rustc_errors/src/diagnostic.rs | 10 ++ compiler/rustc_lint/src/non_fmt_panic.rs | 73 ++++++------- .../const_panic_stability.e2018.stderr | 4 +- src/test/ui/non-fmt-panic.stderr | 100 +++++++++--------- 5 files changed, 132 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 34445c3940a23..39c0e7d3fa616 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -72,3 +72,39 @@ lint-mixed-script-confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes-note = the usage includes {$includes} .note = please recheck to make sure their usages are indeed what you want + +lint-non-fmt-panic = panic message is not a string literal + .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021 + .more-info-note = for more information, see + .supports-fmt-note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here + .supports-fmt-suggestion = remove the `format!(..)` macro call + .display-suggestion = add a "{"{"}{"}"}" format string to `Display` the message + .debug-suggestion = + add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}` + .panic-suggestion = {$already_suggested -> + [true] or use + *[false] use + } std::panic::panic_any instead + +lint-non-fmt-panic-unused = + panic message contains {$count -> + [one] an unused + *[other] unused + } formatting {$count -> + [one] placeholder + *[other] placeholders + } + .note = this message is not used as a format string when given without arguments, but will be in Rust 2021 + .add-args-suggestion = add the missing {$count -> + [one] argument + *[other] arguments + } + .add-fmt-suggestion = or add a "{"{"}{"}"}" format string to use the message literally + +lint-non-fmt-panic-braces = + panic message contains {$count -> + [one] a brace + *[other] braces + } + .note = this message is not used as a format string, but will be in Rust 2021 + .suggestion = add a "{"{"}{"}"}" format string to use the message literally diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index b8545139cecc1..63c0d58bc9cf2 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -39,6 +39,16 @@ pub trait IntoDiagnosticArg { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; } +impl IntoDiagnosticArg for bool { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + if self { + DiagnosticArgValue::Str(Cow::Borrowed("true")) + } else { + DiagnosticArgValue::Str(Cow::Borrowed("false")) + } + } +} + impl IntoDiagnosticArg for String { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::Owned(self)) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 4e7aeca9ce1d5..cdad2d2e8f93e 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -1,6 +1,6 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; -use rustc_errors::{pluralize, Applicability}; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::lint::in_external_macro; @@ -120,9 +120,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| { - let mut l = lint.build("panic message is not a string literal"); - l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol)); - l.note("for more information, see "); + let mut l = lint.build(fluent::lint::non_fmt_panic); + l.set_arg("name", symbol); + l.note(fluent::lint::note); + l.note(fluent::lint::more_info_note); if !is_arg_inside_call(arg_span, span) { // No clue where this argument is coming from. l.emit(); @@ -130,10 +131,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { // A case of `panic!(format!(..))`. - l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol).as_str()); + l.note(fluent::lint::supports_fmt_note); if let Some((open, close, _)) = find_delimiters(cx, arg_span) { l.multipart_suggestion( - "remove the `format!(..)` macro call", + fluent::lint::supports_fmt_suggestion, vec![ (arg_span.until(open.shrink_to_hi()), "".into()), (close.until(arg_span.shrink_to_hi()), "".into()), @@ -153,12 +154,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc ); let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| { - let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { - infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() - }) == Some(true); - let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { - infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() - }) == Some(true); + let display = is_str + || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { + infcx + .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) + .may_apply() + }) == Some(true); + let debug = !display + && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { + infcx + .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env) + .may_apply() + }) == Some(true); (display, debug) }); @@ -175,17 +182,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if suggest_display { l.span_suggestion_verbose( arg_span.shrink_to_lo(), - "add a \"{}\" format string to Display the message", + fluent::lint::display_suggestion, "\"{}\", ", fmt_applicability, ); } else if suggest_debug { + l.set_arg("ty", ty); l.span_suggestion_verbose( arg_span.shrink_to_lo(), - &format!( - "add a \"{{:?}}\" format string to use the Debug implementation of `{}`", - ty, - ), + fluent::lint::debug_suggestion, "\"{:?}\", ", fmt_applicability, ); @@ -193,15 +198,9 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if suggest_panic_any { if let Some((open, close, del)) = find_delimiters(cx, span) { + l.set_arg("already_suggested", suggest_display || suggest_debug); l.multipart_suggestion( - &format!( - "{}use std::panic::panic_any instead", - if suggest_display || suggest_debug { - "or " - } else { - "" - }, - ), + fluent::lint::panic_suggestion, if del == '(' { vec![(span.until(open), "std::panic::panic_any".into())] } else { @@ -260,21 +259,19 @@ fn check_panic_str<'tcx>( .collect(), }; cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| { - let mut l = lint.build(match n_arguments { - 1 => "panic message contains an unused formatting placeholder", - _ => "panic message contains unused formatting placeholders", - }); - l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021"); + let mut l = lint.build(fluent::lint::non_fmt_panic_unused); + l.set_arg("count", n_arguments); + l.note(fluent::lint::note); if is_arg_inside_call(arg.span, span) { l.span_suggestion( arg.span.shrink_to_hi(), - &format!("add the missing argument{}", pluralize!(n_arguments)), + fluent::lint::add_args_suggestion, ", ...", Applicability::HasPlaceholders, ); l.span_suggestion( arg.span.shrink_to_lo(), - "or add a \"{}\" format string to use the message literally", + fluent::lint::add_fmt_suggestion, "\"{}\", ", Applicability::MachineApplicable, ); @@ -289,17 +286,15 @@ fn check_panic_str<'tcx>( .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 })) .collect() }); - let msg = match &brace_spans { - Some(v) if v.len() == 1 => "panic message contains a brace", - _ => "panic message contains braces", - }; + let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2); cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| { - let mut l = lint.build(msg); - l.note("this message is not used as a format string, but will be in Rust 2021"); + let mut l = lint.build(fluent::lint::non_fmt_panic_braces); + l.set_arg("count", count); + l.note(fluent::lint::note); if is_arg_inside_call(arg.span, span) { l.span_suggestion( arg.span.shrink_to_lo(), - "add a \"{}\" format string to use the message literally", + fluent::lint::suggestion, "\"{}\", ", Applicability::MachineApplicable, ); diff --git a/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr b/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr index 94cf64fff1999..f06dedc229845 100644 --- a/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr +++ b/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr @@ -5,9 +5,9 @@ LL | panic!({ "foo" }); | ^^^^^^^^^ | = note: `#[warn(non_fmt_panics)]` on by default - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", { "foo" }); | +++++ diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr index 4da97ed5d60eb..6e4434e6f3372 100644 --- a/src/test/ui/non-fmt-panic.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -73,9 +73,9 @@ warning: panic message is not a string literal LL | assert!(false, S); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", S); | +++++ @@ -86,9 +86,9 @@ warning: panic message is not a string literal LL | assert!(false, 123); | ^^^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", 123); | +++++ @@ -99,9 +99,9 @@ warning: panic message is not a string literal LL | assert!(false, Some(123)); | ^^^^^^^^^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{:?}" format string to use the Debug implementation of `Option` +help: add a "{:?}" format string to use the `Debug` implementation of `Option` | LL | assert!(false, "{:?}", Some(123)); | +++++++ @@ -124,9 +124,9 @@ warning: panic message is not a string literal LL | panic!(C); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", C); | +++++ @@ -137,9 +137,9 @@ warning: panic message is not a string literal LL | panic!(S); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", S); | +++++ @@ -150,9 +150,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); | +++++ @@ -163,9 +163,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); | +++++ @@ -176,9 +176,9 @@ warning: panic message is not a string literal LL | std::panic!(123); | ^^^ | - = note: this usage of std::panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `std::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | std::panic!("{}", 123); | +++++ @@ -193,9 +193,9 @@ warning: panic message is not a string literal LL | core::panic!(&*"abc"); | ^^^^^^^ | - = note: this usage of core::panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `core::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | core::panic!("{}", &*"abc"); | +++++ @@ -206,9 +206,9 @@ warning: panic message is not a string literal LL | panic!(Some(123)); | ^^^^^^^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{:?}" format string to use the Debug implementation of `Option` +help: add a "{:?}" format string to use the `Debug` implementation of `Option` | LL | panic!("{:?}", Some(123)); | +++++++ @@ -259,9 +259,9 @@ warning: panic message is not a string literal LL | panic!(a!()); | ^^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", a!()); | +++++ @@ -276,9 +276,9 @@ warning: panic message is not a string literal LL | unreachable!(a!()); | ^^^^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", a!()); | +++++ @@ -289,9 +289,9 @@ warning: panic message is not a string literal LL | panic!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see - = note: the panic!() macro supports formatting, so there's no need for the format!() macro here + = note: the `panic!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - panic!(format!("{}", 1)); @@ -304,9 +304,9 @@ warning: panic message is not a string literal LL | unreachable!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see - = note: the unreachable!() macro supports formatting, so there's no need for the format!() macro here + = note: the `unreachable!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - unreachable!(format!("{}", 1)); @@ -319,9 +319,9 @@ warning: panic message is not a string literal LL | assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see - = note: the assert!() macro supports formatting, so there's no need for the format!() macro here + = note: the `assert!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - assert!(false, format!("{}", 1)); @@ -334,9 +334,9 @@ warning: panic message is not a string literal LL | debug_assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: this usage of debug_assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `debug_assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see - = note: the debug_assert!() macro supports formatting, so there's no need for the format!() macro here + = note: the `debug_assert!()` macro supports formatting, so there's no need for the `format!()` macro here help: remove the `format!(..)` macro call | LL - debug_assert!(false, format!("{}", 1)); @@ -349,9 +349,9 @@ warning: panic message is not a string literal LL | panic![123]; | ^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!["{}", 123]; | +++++ @@ -366,9 +366,9 @@ warning: panic message is not a string literal LL | panic!{123}; | ^^^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!{"{}", 123}; | +++++ @@ -385,7 +385,7 @@ LL | panic!(v); | | | help: use std::panic::panic_any instead: `std::panic::panic_any` | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see warning: panic message is not a string literal @@ -394,7 +394,7 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see warning: panic message is not a string literal @@ -403,9 +403,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{:?}" format string to use the Debug implementation of `T` +help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | panic!("{:?}", v); | +++++++ @@ -420,9 +420,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{:?}" format string to use the Debug implementation of `T` +help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | assert!(false, "{:?}", v); | +++++++ @@ -433,9 +433,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); | +++++ @@ -450,9 +450,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); | +++++ @@ -463,9 +463,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); | +++++ @@ -480,9 +480,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021 + = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see -help: add a "{}" format string to Display the message +help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); | +++++ From 096a69dd19dc70c6583be329bef7a54010b8ce23 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 16:46:25 +0100 Subject: [PATCH 17/60] lint: port non-standard style diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 16 ++++++++ compiler/rustc_lint/src/nonstandard_style.rs | 40 ++++++++++--------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 39c0e7d3fa616..f0ce4fc02b4a0 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -108,3 +108,19 @@ lint-non-fmt-panic-braces = } .note = this message is not used as a format string, but will be in Rust 2021 .suggestion = add a "{"{"}{"}"}" format string to use the message literally + +lint-non-camel-case-type = {$sort} `{$name}` should have an upper camel case name + .suggestion = convert the identifier to upper camel case + .label = should have an UpperCamelCase name + +lint-non-snake-case = {$sort} `{$name}` should have a snake case name + .rename-or-convert-suggestion = rename the identifier or convert it to a snake case raw identifier + .cannot-convert-note = `{$sc}` cannot be used as a raw identifier + .rename-suggestion = rename the identifier + .convert-suggestion = convert the identifier to snake case + .help = convert the identifier to snake case: `{$sc}` + .label = should have a snake_case name + +lint-non-upper_case-global = {$sort} `{$name}` should have an upper case name + .suggestion = convert the identifier to upper case + .label = should have an UPPER_CASE name diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index e1507d0fbb48f..33ac2ed02aa00 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,7 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; @@ -137,22 +137,23 @@ impl NonCamelCaseTypes { if !is_camel_case(name) { cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| { - let msg = format!("{} `{}` should have an upper camel case name", sort, name); - let mut err = lint.build(&msg); + let mut err = lint.build(fluent::lint::non_camel_case_type); let cc = to_camel_case(name); // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". if *name != cc { err.span_suggestion( ident.span, - "convert the identifier to upper camel case", + fluent::lint::suggestion, to_camel_case(name), Applicability::MaybeIncorrect, ); } else { - err.span_label(ident.span, "should have an UpperCamelCase name"); + err.span_label(ident.span, fluent::lint::label); } + err.set_arg("sort", sort); + err.set_arg("name", name); err.emit(); }) } @@ -281,11 +282,10 @@ impl NonSnakeCase { if !is_snake_case(name) { cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| { let sc = NonSnakeCase::to_snake_case(name); - let msg = format!("{} `{}` should have a snake case name", sort, name); - let mut err = lint.build(&msg); + let mut err = lint.build(fluent::lint::non_snake_case); // We cannot provide meaningful suggestions // if the characters are in the category of "Uppercase Letter". - if *name != sc { + if name != sc { // We have a valid span in almost all cases, but we don't have one when linting a crate // name provided via the command line. if !ident.span.is_dummy() { @@ -295,13 +295,13 @@ impl NonSnakeCase { // Instead, recommend renaming the identifier entirely or, if permitted, // escaping it to create a raw identifier. if sc_ident.name.can_be_raw() { - ("rename the identifier or convert it to a snake case raw identifier", sc_ident.to_string()) + (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string()) } else { - err.note(&format!("`{}` cannot be used as a raw identifier", sc)); - ("rename the identifier", String::new()) + err.note(fluent::lint::cannot_convert_note); + (fluent::lint::rename_suggestion, String::new()) } } else { - ("convert the identifier to snake case", sc) + (fluent::lint::convert_suggestion, sc.clone()) }; err.span_suggestion( @@ -311,12 +311,15 @@ impl NonSnakeCase { Applicability::MaybeIncorrect, ); } else { - err.help(&format!("convert the identifier to snake case: `{}`", sc)); + err.help(fluent::lint::help); } } else { - err.span_label(ident.span, "should have a snake_case name"); + err.span_label(ident.span, fluent::lint::label); } + err.set_arg("sort", sort); + err.set_arg("name", name); + err.set_arg("sc", sc); err.emit(); }); } @@ -488,21 +491,22 @@ impl NonUpperCaseGlobals { if name.chars().any(|c| c.is_lowercase()) { cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| { let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); - let mut err = - lint.build(&format!("{} `{}` should have an upper case name", sort, name)); + let mut err = lint.build(fluent::lint::non_upper_case_global); // We cannot provide meaningful suggestions // if the characters are in the category of "Lowercase Letter". if *name != uc { err.span_suggestion( ident.span, - "convert the identifier to upper case", + fluent::lint::suggestion, uc, Applicability::MaybeIncorrect, ); } else { - err.span_label(ident.span, "should have an UPPER_CASE name"); + err.span_label(ident.span, fluent::lint::label); } + err.set_arg("sort", sort); + err.set_arg("name", name); err.emit(); }) } From 855f23773b3d6a4c14a8d7c92af35f86e990cfb5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 16:52:51 +0100 Subject: [PATCH 18/60] lint: port no-op method call diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 4 ++++ compiler/rustc_lint/src/noop_method_call.rs | 19 +++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index f0ce4fc02b4a0..d93007644dbca 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -124,3 +124,7 @@ lint-non-snake-case = {$sort} `{$name}` should have a snake case name lint-non-upper_case-global = {$sort} `{$name}` should have an upper case name .suggestion = convert the identifier to upper case .label = should have an UPPER_CASE name + +lint-noop-method-call = call to `.{$method}()` on a reference in this situation does nothing + .label = unnecessary method call + .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 675bee738a672..2e847c8b89c56 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -2,6 +2,7 @@ use crate::context::LintContext; use crate::rustc_middle::ty::TypeFoldable; use crate::LateContext; use crate::LateLintPass; +use rustc_errors::fluent; use rustc_hir::def::DefKind; use rustc_hir::{Expr, ExprKind}; use rustc_middle::ty; @@ -80,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { ) { return; } - let method = &call.ident.name; let receiver = &elements[0]; let receiver_ty = cx.typeck_results().expr_ty(receiver); let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); @@ -90,19 +90,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { return; } let expr_span = expr.span; - let note = format!( - "the type `{:?}` which `{}` is being called on is the same as \ - the type returned from `{}`, so the method call does not do \ - anything and can be removed", - receiver_ty, method, method, - ); - let span = expr_span.with_lo(receiver.span.hi()); cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let method = &call.ident.name; - let message = - format!("call to `.{}()` on a reference in this situation does nothing", &method,); - lint.build(&message).span_label(span, "unnecessary method call").note(¬e).emit(); + lint.build(fluent::lint::noop_method_call) + .set_arg("method", call.ident.name) + .set_arg("receiver_ty", receiver_ty) + .span_label(span, fluent::lint::label) + .note(fluent::lint::note) + .emit(); }); } } From 37588d6d4e9ed03ab82d55d9ac14a973c4b641d3 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 16:57:40 +0100 Subject: [PATCH 19/60] lint: port pass-by-value diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/pass_by_value.rs | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index d93007644dbca..e3c588b6ff1ec 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -128,3 +128,6 @@ lint-non-upper_case-global = {$sort} `{$name}` should have an upper case name lint-noop-method-call = call to `.{$method}()` on a reference in this situation does nothing .label = unnecessary method call .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed + +lint-pass-by-value = passing `{$ty}` by reference + .suggestion = try passing by value diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 2c8b41d721403..af5e5faf1f568 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -1,5 +1,5 @@ use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; @@ -30,10 +30,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } if let Some(t) = path_for_pass_by_value(cx, &inner_ty) { cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| { - lint.build(&format!("passing `{}` by reference", t)) + lint.build(fluent::lint::pass_by_value) + .set_arg("ty", t.clone()) .span_suggestion( ty.span, - "try passing by value", + fluent::lint::suggestion, t, // Changing type of function argument Applicability::MaybeIncorrect, From 8e836566f04eef02799609d8e480f3b038270147 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 17:02:46 +0100 Subject: [PATCH 20/60] lint: port redundant semicolons diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 10 ++++++++++ compiler/rustc_lint/src/redundant_semicolon.rs | 12 +++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index e3c588b6ff1ec..511c0baaeca9c 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -131,3 +131,13 @@ lint-noop-method-call = call to `.{$method}()` on a reference in this situation lint-pass-by-value = passing `{$ty}` by reference .suggestion = try passing by value + +lint-redundant-semicolons = + unnecessary trailing {$multiple -> + [true] semicolons + *[false] semicolon + } + .suggestion = remove {$multiple -> + [true] these semicolons + *[false] this semicolon + } diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index f06a8b8f4b0c3..26f41345383f9 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -1,6 +1,6 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast::{Block, StmtKind}; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_span::Span; declare_lint! { @@ -49,12 +49,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo } cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| { - let (msg, rem) = if multiple { - ("unnecessary trailing semicolons", "remove these semicolons") - } else { - ("unnecessary trailing semicolon", "remove this semicolon") - }; - lint.build(msg).span_suggestion(span, rem, "", Applicability::MaybeIncorrect).emit(); + lint.build(fluent::lint::redundant_semicolons) + .set_arg("multiple", multiple) + .span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect) + .emit(); }); } } From 7ef610c003f8072ec4ca4ecf195922a9a44e48dd Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 17:11:53 +0100 Subject: [PATCH 21/60] lint: port drop trait/glue diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 6 ++++++ compiler/rustc_lint/src/traits.rs | 21 +++++++------------ compiler/rustc_middle/src/ty/mod.rs | 6 ++++++ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 511c0baaeca9c..621af76f69584 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -141,3 +141,9 @@ lint-redundant-semicolons = [true] these semicolons *[false] this semicolon } + +lint-drop-trait-constraints = + bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped + +lint-drop-glue = + types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 81d308ee34702..df1587c5948f5 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -1,6 +1,7 @@ use crate::LateContext; use crate::LateLintPass; use crate::LintContext; +use rustc_errors::fluent; use rustc_hir as hir; use rustc_span::symbol::sym; @@ -103,13 +104,10 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; - let msg = format!( - "bounds on `{}` are most likely incorrect, consider instead \ - using `{}` to detect whether a type can be trivially dropped", - predicate, - cx.tcx.def_path_str(needs_drop) - ); - lint.build(&msg).emit(); + lint.build(fluent::lint::drop_trait_constraints) + .set_arg("predicate", predicate) + .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) + .emit(); }); } } @@ -126,12 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; - let msg = format!( - "types that do not implement `Drop` can still have drop glue, consider \ - instead using `{}` to detect whether a type is trivially dropped", - cx.tcx.def_path_str(needs_drop) - ); - lint.build(&msg).emit(); + lint.build(fluent::lint::drop_glue) + .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop)) + .emit(); }); } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 00403ff044c40..1b2d95073d066 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -611,6 +611,12 @@ impl<'a, 'tcx> HashStable> for Predicate<'tcx> { } } +impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub enum PredicateKind<'tcx> { From 7a9bef4d83a091be25fdf0f1beaade66eec0cd92 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 27 Jun 2022 17:42:47 +0100 Subject: [PATCH 22/60] lint: port overflowing literals diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 25 ++++++ compiler/rustc_errors/src/diagnostic.rs | 12 +++ compiler/rustc_lint/src/types.rs | 83 ++++++++++--------- 3 files changed, 79 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 621af76f69584..ae53fb4821b53 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -147,3 +147,28 @@ lint-drop-trait-constraints = lint-drop-glue = types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped + +lint-range-endpoint-out-of-range = range endpoint is out of range for `{$ty}` + .suggestion = use an inclusive range instead + +lint-overflowing-bin-hex = literal out of range for `{$ty}` + .negative-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` + .negative-becomes-note = and the value `-{$lit}` will become `{$actually}{$ty}` + .positive-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` + .suggestion = consider using the type `{$suggestion_ty}` instead + .help = consider using the type `{$suggestion_ty}` instead + +lint-overflowing-int = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + .help = consider using the type `{$suggestion_ty}` instead + +lint-only-cast-u8-to-char = only `u8` can be cast into `char` + .suggestion = use a `char` literal instead + +lint-overflowing-uint = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + +lint-overflowing-literal = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY` + +lint-unused-comparisons = comparison is useless due to type limits diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 63c0d58bc9cf2..576248ae7c230 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -49,6 +49,18 @@ impl IntoDiagnosticArg for bool { } } +impl IntoDiagnosticArg for i128 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for u128 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + impl IntoDiagnosticArg for String { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::Owned(self)) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 5579e4d19cf1f..c92459c770b3e 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -2,7 +2,7 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Applicability; +use rustc_errors::{fluent, Applicability}; use rustc_hir as hir; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; @@ -139,7 +139,8 @@ fn lint_overflowing_range_endpoint<'tcx>( // overflowing and only by 1. if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| { - let mut err = lint.build(&format!("range endpoint is out of range for `{}`", ty)); + let mut err = lint.build(fluent::lint::range_endpoint_out_of_range); + err.set_arg("ty", ty); if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { use ast::{LitIntType, LitKind}; // We need to preserve the literal's suffix, @@ -153,7 +154,7 @@ fn lint_overflowing_range_endpoint<'tcx>( let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); err.span_suggestion( parent_expr.span, - "use an inclusive range instead", + fluent::lint::suggestion, suggestion, Applicability::MachineApplicable, ); @@ -229,38 +230,35 @@ fn report_bin_hex_error( (t.name_str(), actually.to_string()) } }; - let mut err = lint.build(&format!("literal out of range for `{}`", t)); + let mut err = lint.build(fluent::lint::overflowing_bin_hex); if negative { // If the value is negative, // emits a note about the value itself, apart from the literal. - err.note(&format!( - "the literal `{}` (decimal `{}`) does not fit into \ - the type `{}`", - repr_str, val, t - )); - err.note(&format!("and the value `-{}` will become `{}{}`", repr_str, actually, t)); + err.note(fluent::lint::negative_note); + err.note(fluent::lint::negative_becomes_note); } else { - err.note(&format!( - "the literal `{}` (decimal `{}`) does not fit into \ - the type `{}` and will become `{}{}`", - repr_str, val, t, actually, t - )); + err.note(fluent::lint::positive_note); } if let Some(sugg_ty) = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative) { + err.set_arg("suggestion_ty", sugg_ty); if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { let (sans_suffix, _) = repr_str.split_at(pos); err.span_suggestion( expr.span, - &format!("consider using the type `{}` instead", sugg_ty), + fluent::lint::suggestion, format!("{}{}", sans_suffix, sugg_ty), Applicability::MachineApplicable, ); } else { - err.help(&format!("consider using the type `{}` instead", sugg_ty)); + err.help(fluent::lint::help); } } + err.set_arg("ty", t); + err.set_arg("lit", repr_str); + err.set_arg("dec", val); + err.set_arg("actually", actually); err.emit(); }); } @@ -353,21 +351,23 @@ fn lint_int_literal<'tcx>( } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - let mut err = lint.build(&format!("literal out of range for `{}`", t.name_str())); - err.note(&format!( - "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", + let mut err = lint.build(fluent::lint::overflowing_int); + err.set_arg("ty", t.name_str()); + err.set_arg( + "lit", cx.sess() .source_map() .span_to_snippet(lit.span) .expect("must get snippet from literal"), - t.name_str(), - min, - max, - )); + ); + err.set_arg("min", min); + err.set_arg("max", max); + err.note(fluent::lint::note); if let Some(sugg_ty) = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) { - err.help(&format!("consider using the type `{}` instead", sugg_ty)); + err.set_arg("suggestion_ty", sugg_ty); + err.help(fluent::lint::help); } err.emit(); }); @@ -395,10 +395,10 @@ fn lint_uint_literal<'tcx>( hir::ExprKind::Cast(..) => { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| { - lint.build("only `u8` can be cast into `char`") + lint.build(fluent::lint::only_cast_u8_to_char) .span_suggestion( par_e.span, - "use a `char` literal instead", + fluent::lint::suggestion, format!("'\\u{{{:X}}}'", lit_val), Applicability::MachineApplicable, ) @@ -429,17 +429,18 @@ fn lint_uint_literal<'tcx>( return; } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())) - .note(&format!( - "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", + lint.build(fluent::lint::overflowing_uint) + .set_arg("ty", t.name_str()) + .set_arg( + "lit", cx.sess() .source_map() .span_to_snippet(lit.span) .expect("must get snippet from literal"), - t.name_str(), - min, - max, - )) + ) + .set_arg("min", min) + .set_arg("max", max) + .note(fluent::lint::note) .emit(); }); } @@ -471,16 +472,16 @@ fn lint_literal<'tcx>( }; if is_infinite == Ok(true) { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())) - .note(&format!( - "the literal `{}` does not fit into the type `{}` and will be converted to `{}::INFINITY`", + lint.build(fluent::lint::overflowing_literal) + .set_arg("ty", t.name_str()) + .set_arg( + "lit", cx.sess() .source_map() .span_to_snippet(lit.span) .expect("must get snippet from literal"), - t.name_str(), - t.name_str(), - )) + ) + .note(fluent::lint::note) .emit(); }); } @@ -501,7 +502,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { hir::ExprKind::Binary(binop, ref l, ref r) => { if is_comparison(binop) && !check_limits(cx, binop, &l, &r) { cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| { - lint.build("comparison is useless due to type limits").emit(); + lint.build(fluent::lint::unused_comparisons).emit(); }); } } From e5f2e0e16cba9504897f598ca9f384736f9ddce3 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 09:41:49 +0100 Subject: [PATCH 23/60] lint: port improper ctypes diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 58 ++++++++ compiler/rustc_lint/src/types.rs | 129 +++++++++--------- 2 files changed, 124 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index ae53fb4821b53..e9fa3de1b05d7 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -172,3 +172,61 @@ lint-overflowing-literal = literal out of range for `{$ty}` .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY` lint-unused-comparisons = comparison is useless due to type limits + +lint-improper-ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe + .label = not FFI-safe + .note = the type is defined here + +lint-improper-ctypes-opaque = opaque types have no C equivalent + +lint-improper-ctypes-fnptr-reason = this function pointer has Rust-specific calling convention +lint-improper-ctypes-fnptr-help = consider using an `extern fn(...) -> ...` function pointer instead + +lint-improper-ctypes-tuple-reason = tuples have unspecified layout +lint-improper-ctypes-tuple-help = consider using a struct instead + +lint-improper-ctypes-str-reason = string slices have no C equivalent +lint-improper-ctypes-str-help = consider using `*const u8` and a length instead + +lint-improper-ctypes-dyn = trait objects have no C equivalent + +lint-improper-ctypes-slice-reason = slices have no C equivalent +lint-improper-ctypes-slice-help = consider using a raw pointer instead + +lint-improper-ctypes-128bit = 128-bit integers don't currently have a known stable ABI + +lint-improper-ctypes-char-reason = the `char` type has no C equivalent +lint-improper-ctypes-char-help = consider using `u32` or `libc::wchar_t` instead + +lint-improper-ctypes-non-exhaustive = this enum is non-exhaustive +lint-improper-ctypes-non-exhaustive-variant = this enum has non-exhaustive variants + +lint-improper-ctypes-enum-repr-reason = enum has no representation hint +lint-improper-ctypes-enum-repr-help = + consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + +lint-improper-ctypes-struct-fieldless-reason = this struct has no fields +lint-improper-ctypes-struct-fieldless-help = consider adding a member to this struct + +lint-improper-ctypes-union-fieldless-reason = this union has no fields +lint-improper-ctypes-union-fieldless-help = consider adding a member to this union + +lint-improper-ctypes-struct-non-exhaustive = this struct is non-exhaustive +lint-improper-ctypes-union-non-exhaustive = this union is non-exhaustive + +lint-improper-ctypes-struct-layout-reason = this struct has unspecified layout +lint-improper-ctypes-struct-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + +lint-improper-ctypes-union-layout-reason = this union has unspecified layout +lint-improper-ctypes-union-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union + +lint-improper-ctypes-box = box cannot be represented as a single pointer + +lint-improper-ctypes-enum-phantomdata = this enum contains a PhantomData field + +lint-improper-ctypes-struct-zst = this struct contains only zero-sized fields + +lint-improper-ctypes-array-reason = passing raw arrays by value is not FFI-safe +lint-improper-ctypes-array-help = consider passing a pointer to the array + +lint-improper-ctypes-only-phantomdata = composed only of `PhantomData` diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index c92459c770b3e..0b6707645705e 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -2,7 +2,7 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{fluent, Applicability}; +use rustc_errors::{fluent, Applicability, DiagnosticMessage}; use rustc_hir as hir; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; @@ -664,7 +664,7 @@ struct ImproperCTypesVisitor<'a, 'tcx> { enum FfiResult<'tcx> { FfiSafe, FfiPhantom(Ty<'tcx>), - FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option }, + FfiUnsafe { ty: Ty<'tcx>, reason: DiagnosticMessage, help: Option }, } pub(crate) fn nonnull_optimization_guaranteed<'tcx>( @@ -824,8 +824,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.emit_ffi_unsafe_type_lint( ty, sp, - "passing raw arrays by value is not FFI-safe", - Some("consider passing a pointer to the array"), + fluent::lint::improper_ctypes_array_reason, + Some(fluent::lint::improper_ctypes_array_help), ); true } else { @@ -868,11 +868,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { // All fields are ZSTs; this means that the type should behave // like (), which is FFI-unsafe - FfiUnsafe { - ty, - reason: "this struct contains only zero-sized fields".into(), - help: None, - } + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None } } } else { // We can't completely trust repr(C) markings; make sure the fields are @@ -886,7 +882,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiPhantom(..) if def.is_enum() => { return FfiUnsafe { ty, - reason: "this enum contains a PhantomData field".into(), + reason: fluent::lint::improper_ctypes_enum_phantomdata, help: None, }; } @@ -922,7 +918,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } else { return FfiUnsafe { ty, - reason: "box cannot be represented as a single pointer".to_string(), + reason: fluent::lint::improper_ctypes_box, help: None, }; } @@ -932,17 +928,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match def.adt_kind() { AdtKind::Struct | AdtKind::Union => { - let kind = if def.is_struct() { "struct" } else { "union" }; - if !def.repr().c() && !def.repr().transparent() { return FfiUnsafe { ty, - reason: format!("this {} has unspecified layout", kind), - help: Some(format!( - "consider adding a `#[repr(C)]` or \ - `#[repr(transparent)]` attribute to this {}", - kind - )), + reason: if def.is_struct() { + fluent::lint::improper_ctypes_struct_layout_reason + } else { + fluent::lint::improper_ctypes_union_layout_reason + }, + help: if def.is_struct() { + Some(fluent::lint::improper_ctypes_struct_layout_help) + } else { + Some(fluent::lint::improper_ctypes_union_layout_help) + }, }; } @@ -951,7 +949,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if is_non_exhaustive && !def.did().is_local() { return FfiUnsafe { ty, - reason: format!("this {} is non-exhaustive", kind), + reason: if def.is_struct() { + fluent::lint::improper_ctypes_struct_non_exhaustive + } else { + fluent::lint::improper_ctypes_union_non_exhaustive + }, help: None, }; } @@ -959,8 +961,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.non_enum_variant().fields.is_empty() { return FfiUnsafe { ty, - reason: format!("this {} has no fields", kind), - help: Some(format!("consider adding a member to this {}", kind)), + reason: if def.is_struct() { + fluent::lint::improper_ctypes_struct_fieldless_reason + } else { + fluent::lint::improper_ctypes_union_fieldless_reason + }, + help: if def.is_struct() { + Some(fluent::lint::improper_ctypes_struct_fieldless_help) + } else { + Some(fluent::lint::improper_ctypes_union_fieldless_help) + }, }; } @@ -980,13 +990,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if repr_nullable_ptr(self.cx, ty, self.mode).is_none() { return FfiUnsafe { ty, - reason: "enum has no representation hint".into(), - help: Some( - "consider adding a `#[repr(C)]`, \ - `#[repr(transparent)]`, or integer `#[repr(...)]` \ - attribute to this enum" - .into(), - ), + reason: fluent::lint::improper_ctypes_enum_repr_reason, + help: Some(fluent::lint::improper_ctypes_enum_repr_help), }; } } @@ -994,7 +999,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.is_variant_list_non_exhaustive() && !def.did().is_local() { return FfiUnsafe { ty, - reason: "this enum is non-exhaustive".into(), + reason: fluent::lint::improper_ctypes_non_exhaustive, help: None, }; } @@ -1005,7 +1010,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if is_non_exhaustive && !variant.def_id.is_local() { return FfiUnsafe { ty, - reason: "this enum has non-exhaustive variants".into(), + reason: fluent::lint::improper_ctypes_non_exhaustive_variant, help: None, }; } @@ -1023,39 +1028,37 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Char => FfiUnsafe { ty, - reason: "the `char` type has no C equivalent".into(), - help: Some("consider using `u32` or `libc::wchar_t` instead".into()), + reason: fluent::lint::improper_ctypes_char_reason, + help: Some(fluent::lint::improper_ctypes_char_help), }, - ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => FfiUnsafe { - ty, - reason: "128-bit integers don't currently have a known stable ABI".into(), - help: None, - }, + ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None } + } // Primitive types with a stable representation. ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, ty::Slice(_) => FfiUnsafe { ty, - reason: "slices have no C equivalent".into(), - help: Some("consider using a raw pointer instead".into()), + reason: fluent::lint::improper_ctypes_slice_reason, + help: Some(fluent::lint::improper_ctypes_slice_help), }, ty::Dynamic(..) => { - FfiUnsafe { ty, reason: "trait objects have no C equivalent".into(), help: None } + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None } } ty::Str => FfiUnsafe { ty, - reason: "string slices have no C equivalent".into(), - help: Some("consider using `*const u8` and a length instead".into()), + reason: fluent::lint::improper_ctypes_str_reason, + help: Some(fluent::lint::improper_ctypes_str_help), }, ty::Tuple(..) => FfiUnsafe { ty, - reason: "tuples have unspecified layout".into(), - help: Some("consider using a struct instead".into()), + reason: fluent::lint::improper_ctypes_tuple_reason, + help: Some(fluent::lint::improper_ctypes_tuple_help), }, ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) @@ -1086,12 +1089,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if self.is_internal_abi(sig.abi()) { return FfiUnsafe { ty, - reason: "this function pointer has Rust-specific calling convention".into(), - help: Some( - "consider using an `extern fn(...) -> ...` \ - function pointer instead" - .into(), - ), + reason: fluent::lint::improper_ctypes_fnptr_reason, + help: Some(fluent::lint::improper_ctypes_fnptr_help), }; } @@ -1122,7 +1121,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // While opaque types are checked for earlier, if a projection in a struct field // normalizes to an opaque type, then it will reach this branch. ty::Opaque(..) => { - FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None } + FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None } } // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe, @@ -1148,8 +1147,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { &mut self, ty: Ty<'tcx>, sp: Span, - note: &str, - help: Option<&str>, + note: DiagnosticMessage, + help: Option, ) { let lint = match self.mode { CItemKind::Declaration => IMPROPER_CTYPES, @@ -1161,18 +1160,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { CItemKind::Declaration => "block", CItemKind::Definition => "fn", }; - let mut diag = lint.build(&format!( - "`extern` {} uses type `{}`, which is not FFI-safe", - item_description, ty - )); - diag.span_label(sp, "not FFI-safe"); + let mut diag = lint.build(fluent::lint::improper_ctypes); + diag.set_arg("ty", ty); + diag.set_arg("desc", item_description); + diag.span_label(sp, fluent::lint::label); if let Some(help) = help { diag.help(help); } diag.note(note); if let ty::Adt(def, _) = ty.kind() { if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { - diag.span_note(sp, "the type is defined here"); + diag.span_note(sp, fluent::lint::note); } } diag.emit(); @@ -1209,7 +1207,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { - self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None); + self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None); true } else { false @@ -1251,13 +1249,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { FfiResult::FfiSafe => {} FfiResult::FfiPhantom(ty) => { - self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None); + self.emit_ffi_unsafe_type_lint( + ty, + sp, + fluent::lint::improper_ctypes_only_phantomdata, + None, + ); } // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic // argument, which after substitution, is `()`, then this branch can be hit. FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {} FfiResult::FfiUnsafe { ty, reason, help } => { - self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref()); + self.emit_ffi_unsafe_type_lint(ty, sp, reason, help); } } } From 14c3016583a0aad3e7a7dd87b2a13807b420b4e7 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 09:52:05 +0100 Subject: [PATCH 24/60] lint: port variant size difference diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 3 ++ compiler/rustc_errors/src/diagnostic.rs | 48 +++++++++++++++++++ compiler/rustc_lint/src/types.rs | 9 ++-- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index e9fa3de1b05d7..ba2490ab773ea 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -230,3 +230,6 @@ lint-improper-ctypes-array-reason = passing raw arrays by value is not FFI-safe lint-improper-ctypes-array-help = consider passing a pointer to the array lint-improper-ctypes-only-phantomdata = composed only of `PhantomData` + +lint-variant-size-differences = + enum variant is more than three times larger ({$largest} bytes) than the next largest diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 576248ae7c230..03e90b7b0d961 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -49,6 +49,54 @@ impl IntoDiagnosticArg for bool { } } +impl IntoDiagnosticArg for i8 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for u8 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for i16 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for u16 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for i32 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for u32 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for i64 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +impl IntoDiagnosticArg for u64 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + impl IntoDiagnosticArg for i128 { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::Owned(self.to_string())) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 0b6707645705e..dd010040c124d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1387,12 +1387,9 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { VARIANT_SIZE_DIFFERENCES, enum_definition.variants[largest_index].span, |lint| { - lint.build(&format!( - "enum variant is more than three times \ - larger ({} bytes) than the next largest", - largest - )) - .emit(); + lint.build(fluent::lint::variant_size_differences) + .set_arg("largest", largest) + .emit(); }, ); } From 0602729c717181ded09169b021de588b42bee8ee Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 09:59:30 +0100 Subject: [PATCH 25/60] lint: port atomic ordering diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 18 +++++++ compiler/rustc_lint/src/types.rs | 50 +++++++++---------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index ba2490ab773ea..80e8723312e08 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -233,3 +233,21 @@ lint-improper-ctypes-only-phantomdata = composed only of `PhantomData` lint-variant-size-differences = enum variant is more than three times larger ({$largest} bytes) than the next largest + +lint-atomic-ordering-load = atomic loads cannot have `Release` or `AcqRel` ordering + .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +lint-atomic-ordering-store = atomic stores cannot have `Acquire` or `AcqRel` ordering + .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +lint-atomic-ordering-fence = memory fences cannot have `Relaxed` ordering + .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` + +lint-atomic-ordering-invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write + .label = invalid failure ordering + .help = consider using `Acquire` or `Relaxed` failure ordering instead + +lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering + .fail-label = `{$fail_ordering}` failure ordering + .success-label = `{$success_ordering}` success ordering + .suggestion = consider using `{$success_suggestion}` success ordering instead diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index dd010040c124d..0056872ee44c3 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1512,13 +1512,13 @@ impl InvalidAtomicOrdering { { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| { if method == sym::load { - diag.build("atomic loads cannot have `Release` or `AcqRel` ordering") - .help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`") + diag.build(fluent::lint::atomic_ordering_load) + .help(fluent::lint::help) .emit() } else { debug_assert_eq!(method, sym::store); - diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering") - .help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`") + diag.build(fluent::lint::atomic_ordering_store) + .help(fluent::lint::help) .emit(); } }); @@ -1533,8 +1533,8 @@ impl InvalidAtomicOrdering { && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed) { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| { - diag.build("memory fences cannot have `Relaxed` ordering") - .help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`") + diag.build(fluent::lint::atomic_ordering_fence) + .help(fluent::lint::help) .emit(); }); } @@ -1554,13 +1554,11 @@ impl InvalidAtomicOrdering { if matches!(fail_ordering, sym::Release | sym::AcqRel) { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg.span, |diag| { - diag.build(&format!( - "`{method}`'s failure ordering may not be `Release` or `AcqRel`, \ - since a failed `{method}` does not result in a write", - )) - .span_label(fail_order_arg.span, "invalid failure ordering") - .help("consider using `Acquire` or `Relaxed` failure ordering instead") - .emit(); + diag.build(fluent::lint::atomic_ordering_invalid) + .set_arg("method", method) + .span_label(fail_order_arg.span, fluent::lint::label) + .help(fluent::lint::help) + .emit(); }); } @@ -1578,18 +1576,20 @@ impl InvalidAtomicOrdering { fail_ordering }; cx.struct_span_lint(INVALID_ATOMIC_ORDERING, success_order_arg.span, |diag| { - diag.build(&format!( - "`{method}`'s success ordering must be at least as strong as its failure ordering" - )) - .span_label(fail_order_arg.span, format!("`{fail_ordering}` failure ordering")) - .span_label(success_order_arg.span, format!("`{success_ordering}` success ordering")) - .span_suggestion_short( - success_order_arg.span, - format!("consider using `{success_suggestion}` success ordering instead"), - format!("std::sync::atomic::Ordering::{success_suggestion}"), - Applicability::MaybeIncorrect, - ) - .emit(); + diag.build(fluent::lint::atomic_ordering_invalid_fail_success) + .set_arg("method", method) + .set_arg("fail_ordering", fail_ordering) + .set_arg("success_ordering", success_ordering) + .set_arg("success_suggestion", success_suggestion) + .span_label(fail_order_arg.span, fluent::lint::fail_label) + .span_label(success_order_arg.span, fluent::lint::success_label) + .span_suggestion_short( + success_order_arg.span, + fluent::lint::suggestion, + format!("std::sync::atomic::Ordering::{success_suggestion}"), + Applicability::MaybeIncorrect, + ) + .emit(); }); } } From 1999a4c42181b269e9f61a329333069e707604ec Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:14:10 +0100 Subject: [PATCH 26/60] lint: port unused diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 22 +++++++ compiler/rustc_lint/src/unused.rs | 64 ++++++++++--------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 80e8723312e08..c673ec7785db7 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -251,3 +251,25 @@ lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must .fail-label = `{$fail_ordering}` failure ordering .success-label = `{$success_ordering}` success ordering .suggestion = consider using `{$success_suggestion}` success ordering instead + +lint-unused-op = unused {$op} that must be used + .label = the {$op} produces a value + .suggestion = use `let _ = ...` to ignore the resulting value + +lint-unused-result = unused result of type `{$ty}` + +lint-unused-closure = + unused {$pre}{$count -> + [one] closure + *[other] closures + }{$post} that must be used + .note = closures are lazy and do nothing unless called + +lint-unused-generator = + unused {$pre}{$count -> + [one] generator + *[other] generator + }{$post} that must be used + .note = generators are lazy and do nothing unless resumed + +lint-unused-def = unused {$pre}`{$def}`{$post} that must be used diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 73f353e62c177..d3cb3a70f02e1 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; -use rustc_errors::{pluralize, Applicability, MultiSpan}; +use rustc_errors::{fluent, pluralize, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -155,22 +155,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { if let Some(must_use_op) = must_use_op { cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| { - let mut lint = lint.build(&format!("unused {} that must be used", must_use_op)); - lint.span_label(expr.span, &format!("the {} produces a value", must_use_op)); - lint.span_suggestion_verbose( - expr.span.shrink_to_lo(), - "use `let _ = ...` to ignore the resulting value", - "let _ = ", - Applicability::MachineApplicable, - ); - lint.emit(); + lint.build(fluent::lint::unused_op) + .set_arg("op", must_use_op) + .span_label(expr.span, fluent::lint::label) + .span_suggestion_verbose( + expr.span.shrink_to_lo(), + fluent::lint::suggestion, + "let _ = ", + Applicability::MachineApplicable, + ) + .emit(); }); op_warned = true; } if !(type_permits_lack_of_use || fn_warned || op_warned) { cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| { - lint.build(&format!("unused result of type `{}`", ty)).emit(); + lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit(); }); } @@ -267,23 +268,27 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { }, ty::Closure(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - let mut err = lint.build(&format!( - "unused {}closure{}{} that must be used", - descr_pre, plural_suffix, descr_post, - )); - err.note("closures are lazy and do nothing unless called"); - err.emit(); + // FIXME(davidtwco): this isn't properly translatable becauses of the + // pre/post strings + lint.build(fluent::lint::unused_closure) + .set_arg("count", plural_len) + .set_arg("pre", descr_pre) + .set_arg("post", descr_post) + .note(fluent::lint::note) + .emit(); }); true } ty::Generator(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - let mut err = lint.build(&format!( - "unused {}generator{}{} that must be used", - descr_pre, plural_suffix, descr_post, - )); - err.note("generators are lazy and do nothing unless resumed"); - err.emit(); + // FIXME(davidtwco): this isn't properly translatable becauses of the + // pre/post strings + lint.build(fluent::lint::unused_generator) + .set_arg("count", plural_len) + .set_arg("pre", descr_pre) + .set_arg("post", descr_post) + .note(fluent::lint::note) + .emit(); }); true } @@ -305,13 +310,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ) -> bool { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - let msg = format!( - "unused {}`{}`{} that must be used", - descr_pre_path, - cx.tcx.def_path_str(def_id), - descr_post_path - ); - let mut err = lint.build(&msg); + // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post + // strings + let mut err = lint.build(fluent::lint::unused_def); + err.set_arg("pre", descr_pre_path); + err.set_arg("post", descr_post_path); + err.set_arg("def", cx.tcx.def_path_str(def_id)); // check for #[must_use = "..."] if let Some(note) = attr.value_str() { err.note(note.as_str()); From 2829f519a068addbbac9627a3d62951614677766 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:19:11 +0100 Subject: [PATCH 27/60] lint: port path statement diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 5 +++++ compiler/rustc_lint/src/unused.rs | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index c673ec7785db7..e14912630dddc 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -273,3 +273,8 @@ lint-unused-generator = .note = generators are lazy and do nothing unless resumed lint-unused-def = unused {$pre}`{$def}`{$post} that must be used + +lint-path-statement-drop = path statement drops value + .suggestion = use `drop` to clarify the intent + +lint-path-statement-no-effect = path statement with no effect diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index d3cb3a70f02e1..a3a879b333b48 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -360,20 +360,20 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements { cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| { let ty = cx.typeck_results().expr_ty(expr); if ty.needs_drop(cx.tcx, cx.param_env) { - let mut lint = lint.build("path statement drops value"); + let mut lint = lint.build(fluent::lint::path_statement_drop); if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) { lint.span_suggestion( s.span, - "use `drop` to clarify the intent", + fluent::lint::suggestion, format!("drop({});", snippet), Applicability::MachineApplicable, ); } else { - lint.span_help(s.span, "use `drop` to clarify the intent"); + lint.span_help(s.span, fluent::lint::suggestion); } lint.emit(); } else { - lint.build("path statement with no effect").emit(); + lint.build(fluent::lint::path_statement_no_effect).emit(); } }); } From fc4f8d9bc24ef3e3e3be6c22cbcab85adf21cf2d Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:28:57 +0100 Subject: [PATCH 28/60] lint: port unused delimiter diagnostics Signed-off-by: David Wood --- .../rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/unused.rs | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index e14912630dddc..00ac64031ca40 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -278,3 +278,6 @@ lint-path-statement-drop = path statement drops value .suggestion = use `drop` to clarify the intent lint-path-statement-no-effect = path statement with no effect + +lint-unused-delim = unnecessary {$delim} around {$item} + .suggestion = remove these {$delim} diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a3a879b333b48..e163c9add31b0 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -544,15 +544,19 @@ trait UnusedDelimLint { } cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| { - let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg); - let mut err = lint.build(&span_msg); let replacement = vec![ (spans.0, if keep_space.0 { " ".into() } else { "".into() }), (spans.1, if keep_space.1 { " ".into() } else { "".into() }), ]; - let suggestion = format!("remove these {}", Self::DELIM_STR); - err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable); - err.emit(); + lint.build(fluent::lint::unused_delim) + .set_arg("delim", Self::DELIM_STR) + .set_arg("item", msg) + .multipart_suggestion( + fluent::lint::suggestion, + replacement, + Applicability::MachineApplicable, + ) + .emit(); }); } From e24833869f17b9032a1fbea69adfdd1e615918b9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:32:57 +0100 Subject: [PATCH 29/60] lint: port unused import braces diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/unused.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 00ac64031ca40..7a2635eae2d97 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -281,3 +281,5 @@ lint-path-statement-no-effect = path statement with no effect lint-unused-delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} + +lint-unused-import-braces = braces around {$node} is unnecessary diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index e163c9add31b0..6fcabde3406bd 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1118,7 +1118,7 @@ impl UnusedImportBraces { }; cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| { - lint.build(&format!("braces around {} is unnecessary", node_name)).emit(); + lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit(); }); } } From 4f7b10f484a42442c3e28bfbb62960460eba85f5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:43:38 +0100 Subject: [PATCH 30/60] lint: port unused allocation diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/unused.rs | 12 +++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 7a2635eae2d97..11dfe4fe81070 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -283,3 +283,6 @@ lint-unused-delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} lint-unused-import-braces = braces around {$node} is unnecessary + +lint-unused-allocation = unnecessary allocation, use `&` instead +lint-unused-allocation-mut = unnecessary allocation, use `&mut` instead diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 6fcabde3406bd..53269d1852703 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1169,15 +1169,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { for adj in cx.typeck_results().expr_adjustments(e) { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| { - let msg = match m { - adjustment::AutoBorrowMutability::Not => { - "unnecessary allocation, use `&` instead" - } + lint.build(match m { + adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation, adjustment::AutoBorrowMutability::Mut { .. } => { - "unnecessary allocation, use `&mut` instead" + fluent::lint::unused_allocation_mut } - }; - lint.build(msg).emit(); + }) + .emit(); }); } } From 588977b3508e2c84bfab3467280a9a14c0cfa95a Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:55:42 +0100 Subject: [PATCH 31/60] lint: port while true diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/builtin.rs | 7 +++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 11dfe4fe81070..e1903470fce9f 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -286,3 +286,6 @@ lint-unused-import-braces = braces around {$node} is unnecessary lint-unused-allocation = unnecessary allocation, use `&` instead lint-unused-allocation-mut = unnecessary allocation, use `&mut` instead + +lint-builtin-while-true = denote infinite loops with `loop {"{"} ... {"}"}` + .suggestion = use `loop` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8266f1566c423..9640184fda3f2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -31,7 +31,7 @@ use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{Applicability, Diagnostic, DiagnosticStyledString, MultiSpan}; +use rustc_errors::{fluent, Applicability, Diagnostic, DiagnosticStyledString, MultiSpan}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -99,13 +99,12 @@ impl EarlyLintPass for WhileTrue { if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind { if let ast::LitKind::Bool(true) = lit.kind { if !lit.span.from_expansion() { - let msg = "denote infinite loops with `loop { ... }`"; let condition_span = e.span.with_hi(cond.span.hi()); cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { - lint.build(msg) + lint.build(fluent::lint::builtin_while_true) .span_suggestion_short( condition_span, - "use `loop`", + fluent::lint::suggestion, format!( "{}loop", label.map_or_else(String::new, |label| format!( From d433c9a4464110134d749f22163b1b3f108f2614 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:56:01 +0100 Subject: [PATCH 32/60] lint: port box pointers diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index e1903470fce9f..34e211ba1dfa2 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -289,3 +289,5 @@ lint-unused-allocation-mut = unnecessary allocation, use `&mut` instead lint-builtin-while-true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` + +lint-builtin-box-pointers = type uses owned (Box type) pointers: {$ty} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9640184fda3f2..815916ac9e8ed 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -155,7 +155,7 @@ impl BoxPointers { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if leaf_ty.is_box() { cx.struct_span_lint(BOX_POINTERS, span, |lint| { - lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit(); + lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit(); }); } } From 4c63a2145c171bdf498c56f0c923baa7c135bb20 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:56:18 +0100 Subject: [PATCH 33/60] lint: port non-shorthand pattern diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/builtin.rs | 20 +++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 34e211ba1dfa2..a549c9fd98af0 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -291,3 +291,6 @@ lint-builtin-while-true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` lint-builtin-box-pointers = type uses owned (Box type) pointers: {$ty} + +lint-builtin-non-shorthand-field-patterns = the `{$ident}:` in this pattern is redundant + .suggestion = use shorthand field pattern diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 815916ac9e8ed..ed51a446c5a64 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -256,26 +256,26 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results())) { cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| { - let mut err = lint - .build(&format!("the `{}:` in this pattern is redundant", ident)); let binding = match binding_annot { hir::BindingAnnotation::Unannotated => None, hir::BindingAnnotation::Mutable => Some("mut"), hir::BindingAnnotation::Ref => Some("ref"), hir::BindingAnnotation::RefMut => Some("ref mut"), }; - let ident = if let Some(binding) = binding { + let suggested_ident = if let Some(binding) = binding { format!("{} {}", binding, ident) } else { ident.to_string() }; - err.span_suggestion( - fieldpat.span, - "use shorthand field pattern", - ident, - Applicability::MachineApplicable, - ); - err.emit(); + lint.build(fluent::lint::builtin_non_shorthand_field_patterns) + .set_arg("ident", ident.clone()) + .span_suggestion( + fieldpat.span, + fluent::lint::suggestion, + suggested_ident, + Applicability::MachineApplicable, + ) + .emit(); }); } } From 7dffd14b9642d4b6787b15001a0107f577b6379b Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:57:05 +0100 Subject: [PATCH 34/60] lint: port unsafe diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 30 ++++++++ compiler/rustc_lint/src/builtin.rs | 68 +++++++++---------- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index a549c9fd98af0..359ae8db5892c 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -294,3 +294,33 @@ lint-builtin-box-pointers = type uses owned (Box type) pointers: {$ty} lint-builtin-non-shorthand-field-patterns = the `{$ident}:` in this pattern is redundant .suggestion = use shorthand field pattern + +lint-builtin-overridden-symbol-name = + the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +lint-builtin-overridden-symbol-section = + the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them + +lint-builtin-allow-internal-unsafe = + `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site + +lint-builtin-unsafe-block = usage of an `unsafe` block + +lint-builtin-unsafe-trait = declaration of an `unsafe` trait + +lint-builtin-unsafe-impl = implementation of an `unsafe` trait + +lint-builtin-no-mangle-fn = declaration of a `no_mangle` function +lint-builtin-export-name-fn = declaration of a function with `export_name` +lint-builtin-link-section-fn = declaration of a function with `link_section` + +lint-builtin-no-mangle-static = declaration of a `no_mangle` static +lint-builtin-export-name-static = declaration of a static with `export_name` +lint-builtin-link-section-static = declaration of a static with `link_section` + +lint-builtin-no-mangle-method = declaration of a `no_mangle` method +lint-builtin-export-name-method = declaration of a method with `export_name` + +lint-builtin-decl-unsafe-fn = declaration of an `unsafe` function +lint-builtin-decl-unsafe-method = declaration of an `unsafe` method +lint-builtin-impl-unsafe-method = implementation of an `unsafe` method diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ed51a446c5a64..6acfbc8f89b37 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -31,7 +31,9 @@ use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{fluent, Applicability, Diagnostic, DiagnosticStyledString, MultiSpan}; +use rustc_errors::{ + fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, MultiSpan, +}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -326,26 +328,25 @@ impl UnsafeCode { cx.struct_span_lint(UNSAFE_CODE, span, decorate); } - fn report_overridden_symbol_name(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) { + fn report_overridden_symbol_name( + &self, + cx: &EarlyContext<'_>, + span: Span, + msg: DiagnosticMessage, + ) { self.report_unsafe(cx, span, |lint| { - lint.build(msg) - .note( - "the linker's behavior with multiple libraries exporting duplicate symbol \ - names is undefined and Rust cannot provide guarantees when you manually \ - override them", - ) - .emit(); + lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit(); }) } - fn report_overridden_symbol_section(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) { + fn report_overridden_symbol_section( + &self, + cx: &EarlyContext<'_>, + span: Span, + msg: DiagnosticMessage, + ) { self.report_unsafe(cx, span, |lint| { - lint.build(msg) - .note( - "the program's behavior with overridden link sections on items is unpredictable \ - and Rust cannot provide guarantees when you manually override them", - ) - .emit(); + lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit(); }) } } @@ -354,12 +355,7 @@ impl EarlyLintPass for UnsafeCode { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { if attr.has_name(sym::allow_internal_unsafe) { self.report_unsafe(cx, attr.span, |lint| { - lint.build( - "`allow_internal_unsafe` allows defining \ - macros using unsafe without triggering \ - the `unsafe_code` lint at their call site", - ) - .emit(); + lint.build(fluent::lint::builtin_allow_internal_unsafe).emit(); }); } } @@ -369,7 +365,7 @@ impl EarlyLintPass for UnsafeCode { // Don't warn about generated blocks; that'll just pollute the output. if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { self.report_unsafe(cx, blk.span, |lint| { - lint.build("usage of an `unsafe` block").emit(); + lint.build(fluent::lint::builtin_unsafe_block).emit(); }); } } @@ -379,12 +375,12 @@ impl EarlyLintPass for UnsafeCode { match it.kind { ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self .report_unsafe(cx, it.span, |lint| { - lint.build("declaration of an `unsafe` trait").emit(); + lint.build(fluent::lint::builtin_unsafe_trait).emit(); }), ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self .report_unsafe(cx, it.span, |lint| { - lint.build("implementation of an `unsafe` trait").emit(); + lint.build(fluent::lint::builtin_unsafe_impl).emit(); }), ast::ItemKind::Fn(..) => { @@ -392,7 +388,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a `no_mangle` function", + fluent::lint::builtin_no_mangle_fn, ); } @@ -400,7 +396,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a function with `export_name`", + fluent::lint::builtin_export_name_fn, ); } @@ -408,7 +404,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_section( cx, attr.span, - "declaration of a function with `link_section`", + fluent::lint::builtin_link_section_fn, ); } } @@ -418,7 +414,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a `no_mangle` static", + fluent::lint::builtin_no_mangle_static, ); } @@ -426,7 +422,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a static with `export_name`", + fluent::lint::builtin_export_name_static, ); } @@ -434,7 +430,7 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_section( cx, attr.span, - "declaration of a static with `link_section`", + fluent::lint::builtin_link_section_static, ); } } @@ -449,14 +445,14 @@ impl EarlyLintPass for UnsafeCode { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a `no_mangle` method", + fluent::lint::builtin_no_mangle_method, ); } if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { self.report_overridden_symbol_name( cx, attr.span, - "declaration of a method with `export_name`", + fluent::lint::builtin_export_name_method, ); } } @@ -474,9 +470,9 @@ impl EarlyLintPass for UnsafeCode { { let msg = match ctxt { FnCtxt::Foreign => return, - FnCtxt::Free => "declaration of an `unsafe` function", - FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method", - FnCtxt::Assoc(_) => "implementation of an `unsafe` method", + FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn, + FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method, + FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method, }; self.report_unsafe(cx, span, |lint| { lint.build(msg).emit(); From 82bd2c23e5a1525659ea5b59e304fb7afbcab388 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 10:57:19 +0100 Subject: [PATCH 35/60] lint: port missing documentation diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 359ae8db5892c..4c84746f3d6dc 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -324,3 +324,5 @@ lint-builtin-export-name-method = declaration of a method with `export_name` lint-builtin-decl-unsafe-fn = declaration of an `unsafe` function lint-builtin-decl-unsafe-method = declaration of an `unsafe` method lint-builtin-impl-unsafe-method = implementation of an `unsafe` method + +lint-builtin-missing-doc = missing documentation for {$article} {$desc} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6acfbc8f89b37..cf28cdd9bce92 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -582,7 +582,10 @@ impl MissingDoc { MISSING_DOCS, cx.tcx.sess.source_map().guess_head_span(sp), |lint| { - lint.build(&format!("missing documentation for {} {}", article, desc)).emit(); + lint.build(fluent::lint::builtin_missing_doc) + .set_arg("article", article) + .set_arg("desc", desc) + .emit(); }, ); } From 28655bc95537efa467dde736b9c1ded59b95b564 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 11:23:11 +0100 Subject: [PATCH 36/60] lint: port missing copy impl diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 6 +----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 4c84746f3d6dc..7375e4fcadbc7 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -326,3 +326,5 @@ lint-builtin-decl-unsafe-method = declaration of an `unsafe` method lint-builtin-impl-unsafe-method = implementation of an `unsafe` method lint-builtin-missing-doc = missing documentation for {$article} {$desc} + +lint-builtin-missing-copy-impl = type could implement `Copy`; consider adding `impl Copy` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index cf28cdd9bce92..c33e9561c1aa4 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -781,11 +781,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { .is_ok() { cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| { - lint.build( - "type could implement `Copy`; consider adding `impl \ - Copy`", - ) - .emit(); + lint.build(fluent::lint::builtin_missing_copy_impl).emit(); }) } } From 284ec37810f7d93cee6fd0a177220fc55afb7755 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 11:27:26 +0100 Subject: [PATCH 37/60] lint: port missing debug impl diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/builtin.rs | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 7375e4fcadbc7..fd1d1a8dc2fd3 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -328,3 +328,6 @@ lint-builtin-impl-unsafe-method = implementation of an `unsafe` method lint-builtin-missing-doc = missing documentation for {$article} {$desc} lint-builtin-missing-copy-impl = type could implement `Copy`; consider adding `impl Copy` + +lint-builtin-missing-debug-impl = + type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c33e9561c1aa4..82b283ad4b52b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -857,12 +857,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { if !self.impling_types.as_ref().unwrap().contains(&item.def_id) { cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| { - lint.build(&format!( - "type does not implement `{}`; consider adding `#[derive(Debug)]` \ - or a manual implementation", - cx.tcx.def_path_str(debug) - )) - .emit(); + lint.build(fluent::lint::builtin_missing_debug_impl) + .set_arg("debug", cx.tcx.def_path_str(debug)) + .emit(); }); } } From 18a48c1d6c7815eb56bac3798819a3d109e5c95c Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 11:31:44 +0100 Subject: [PATCH 38/60] lint: port anonymous parameter diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/builtin.rs | 20 ++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index fd1d1a8dc2fd3..4f8366bbedb46 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -331,3 +331,6 @@ lint-builtin-missing-copy-impl = type could implement `Copy`; consider adding `i lint-builtin-missing-debug-impl = type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation + +lint-builtin-anonymous-params = anonymous parameters are deprecated and will be removed in the next edition + .suggestion = try naming the parameter or explicitly ignoring it diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 82b283ad4b52b..b14a3294fbcdb 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -937,18 +937,14 @@ impl EarlyLintPass for AnonymousParameters { ("", Applicability::HasPlaceholders) }; - lint.build( - "anonymous parameters are deprecated and will be \ - removed in the next edition", - ) - .span_suggestion( - arg.pat.span, - "try naming the parameter or explicitly \ - ignoring it", - format!("_: {}", ty_snip), - appl, - ) - .emit(); + lint.build(fluent::lint::builtin_anonymous_params) + .span_suggestion( + arg.pat.span, + fluent::lint::suggestion, + format!("_: {}", ty_snip), + appl, + ) + .emit(); }) } } From e151d66343788875c039a13dad8e3e90831565c1 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 11:51:15 +0100 Subject: [PATCH 39/60] lint: port deprecated attr diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 4 ++ compiler/rustc_lint/src/builtin.rs | 51 ++++++++++--------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 4f8366bbedb46..74a6e7ecdb568 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -334,3 +334,7 @@ lint-builtin-missing-debug-impl = lint-builtin-anonymous-params = anonymous parameters are deprecated and will be removed in the next edition .suggestion = try naming the parameter or explicitly ignoring it + +lint-builtin-deprecated-attr-link = use of deprecated attribute `{$name}`: {$reason}. See {$link} +lint-builtin-deprecated-attr-used = use of deprecated attribute `{$name}`: no longer used. +lint-builtin-deprecated-attr-default-suggestion = remove this attribute diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b14a3294fbcdb..147c4e94326e4 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -969,24 +969,6 @@ impl DeprecatedAttr { } } -fn lint_deprecated_attr( - cx: &EarlyContext<'_>, - attr: &ast::Attribute, - msg: &str, - suggestion: Option<&str>, -) { - cx.struct_span_lint(DEPRECATED, attr.span, |lint| { - lint.build(msg) - .span_suggestion_short( - attr.span, - suggestion.unwrap_or("remove this attribute"), - "", - Applicability::MachineApplicable, - ) - .emit(); - }) -} - impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { for BuiltinAttribute { name, gate, .. } in &self.depr_attrs { @@ -998,17 +980,38 @@ impl EarlyLintPass for DeprecatedAttr { _, ) = gate { - let msg = - format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link); - lint_deprecated_attr(cx, attr, &msg, suggestion); + cx.struct_span_lint(DEPRECATED, attr.span, |lint| { + // FIXME(davidtwco) translatable deprecated attr + lint.build(fluent::lint::builtin_deprecated_attr_link) + .set_arg("name", name) + .set_arg("reason", reason) + .set_arg("link", link) + .span_suggestion_short( + attr.span, + suggestion.map(|s| s.into()).unwrap_or( + fluent::lint::builtin_deprecated_attr_default_suggestion, + ), + "", + Applicability::MachineApplicable, + ) + .emit(); + }); } return; } } if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) { - let path_str = pprust::path_to_string(&attr.get_normal_item().path); - let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); - lint_deprecated_attr(cx, attr, &msg, None); + cx.struct_span_lint(DEPRECATED, attr.span, |lint| { + lint.build(fluent::lint::builtin_deprecated_attr_used) + .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path)) + .span_suggestion_short( + attr.span, + fluent::lint::builtin_deprecated_attr_default_suggestion, + "", + Applicability::MachineApplicable, + ) + .emit(); + }); } } } From a13b70ea83f1f3781cba2dbdc990520bdbb6a740 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 13:35:33 +0100 Subject: [PATCH 40/60] lint: port unused doc comment diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 5 +++++ compiler/rustc_lint/src/builtin.rs | 12 +++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 74a6e7ecdb568..3de652e309343 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -338,3 +338,8 @@ lint-builtin-anonymous-params = anonymous parameters are deprecated and will be lint-builtin-deprecated-attr-link = use of deprecated attribute `{$name}`: {$reason}. See {$link} lint-builtin-deprecated-attr-used = use of deprecated attribute `{$name}`: no longer used. lint-builtin-deprecated-attr-default-suggestion = remove this attribute + +lint-builtin-unused-doc-comment = unused doc comment + .label = rustdoc does not generate documentation for {$kind} + .plain-help = use `//` for a plain comment + .block-help = use `/* */` for a plain comment diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 147c4e94326e4..a31936f376afd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1039,17 +1039,15 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & if is_doc_comment || attr.has_name(sym::doc) { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { - let mut err = lint.build("unused doc comment"); - err.span_label( - node_span, - format!("rustdoc does not generate documentation for {}", node_kind), - ); + let mut err = lint.build(fluent::lint::builtin_unused_doc_comment); + err.set_arg("kind", node_kind); + err.span_label(node_span, fluent::lint::label); match attr.kind { AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { - err.help("use `//` for a plain comment"); + err.help(fluent::lint::plain_help); } AttrKind::DocComment(CommentKind::Block, _) => { - err.help("use `/* */` for a plain comment"); + err.help(fluent::lint::block_help); } } err.emit(); From dbdbdb68740dd3be9cea059dd5cb6067c45f38d7 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 13:40:59 +0100 Subject: [PATCH 41/60] lint: port no-mangle diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 6 ++++++ compiler/rustc_lint/src/builtin.rs | 9 ++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 3de652e309343..cbe7e15a723db 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -343,3 +343,9 @@ lint-builtin-unused-doc-comment = unused doc comment .label = rustdoc does not generate documentation for {$kind} .plain-help = use `//` for a plain comment .block-help = use `/* */` for a plain comment + +lint-builtin-no-mangle-generic = functions generic over types or consts must be mangled + .suggestion = remove this attribute + +lint-builtin-const-no-mangle = const items should never be `#[no_mangle]` + .suggestion = try a static value diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a31936f376afd..6dfcc0eec49ae 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1166,10 +1166,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| { - lint.build("functions generic over types or consts must be mangled") + lint.build(fluent::lint::builtin_no_mangle_generic) .span_suggestion_short( no_mangle_attr.span, - "remove this attribute", + fluent::lint::suggestion, "", // Use of `#[no_mangle]` suggests FFI intent; correct // fix may be to monomorphize source by hand @@ -1193,8 +1193,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| { - let msg = "const items should never be `#[no_mangle]`"; - let mut err = lint.build(msg); + let mut err = lint.build(fluent::lint::builtin_const_no_mangle); // account for "pub const" (#45562) let start = cx @@ -1208,7 +1207,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); err.span_suggestion( const_span, - "try a static value", + fluent::lint::suggestion, "pub static", Applicability::MachineApplicable, ); From d071f504f80767b1686b176b72fdcf87a35f8dca Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 13:45:49 +0100 Subject: [PATCH 42/60] lint: port mutable transmutes diagnostic Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/builtin.rs | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index cbe7e15a723db..de2d21ff355ff 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -349,3 +349,6 @@ lint-builtin-no-mangle-generic = functions generic over types or consts must be lint-builtin-const-no-mangle = const items should never be `#[no_mangle]` .suggestion = try a static value + +lint-builtin-mutable-transmutes = + transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6dfcc0eec49ae..c2729b543c4de 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1272,10 +1272,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { - let msg = "transmuting &T to &mut T is undefined behavior, \ - even if the reference is unused, consider instead using an UnsafeCell"; cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| { - lint.build(msg).emit(); + lint.build(fluent::lint::builtin_mutable_transmutes).emit(); }); } } From 23ee3e09141fd01ba3ec648123aa319810867c86 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 13:50:44 +0100 Subject: [PATCH 43/60] lint: port unstable feature diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index de2d21ff355ff..7c6a17aec58b6 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -352,3 +352,5 @@ lint-builtin-const-no-mangle = const items should never be `#[no_mangle]` lint-builtin-mutable-transmutes = transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell + +lint-builtin-unstable-features = unstable feature diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c2729b543c4de..4787d2ee92a81 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1323,7 +1323,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { if let Some(items) = attr.meta_item_list() { for item in items { cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| { - lint.build("unstable feature").emit(); + lint.build(fluent::lint::builtin_unstable_features).emit(); }); } } From dbced105db2b417d40b90a55c4c1a68a4f0ee6aa Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 13:55:12 +0100 Subject: [PATCH 44/60] lint: port unreachable `pub` diagnostic Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 4 ++++ compiler/rustc_lint/src/builtin.rs | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 7c6a17aec58b6..34ce4b9d96751 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -354,3 +354,7 @@ lint-builtin-mutable-transmutes = transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell lint-builtin-unstable-features = unstable feature + +lint-builtin-unreachable-pub = unreachable `pub` {$what} + .suggestion = consider restricting its visibility + .help = or consider exporting it for use by other crates diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 4787d2ee92a81..6c21936629170 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1385,16 +1385,17 @@ impl UnreachablePub { } let def_span = cx.tcx.sess.source_map().guess_head_span(span); cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| { - let mut err = lint.build(&format!("unreachable `pub` {}", what)); + let mut err = lint.build(fluent::lint::builtin_unreachable_pub); + err.set_arg("what", what); err.span_suggestion( vis_span, - "consider restricting its visibility", + fluent::lint::suggestion, "pub(crate)", applicability, ); if exportable { - err.help("or consider exporting it for use by other crates"); + err.help(fluent::lint::help); } err.emit(); }); From 01a64af4dd30a95e52f525ba621ff05c236b3931 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:04:42 +0100 Subject: [PATCH 45/60] lint: port type alias bounds diagnostics Signed-off-by: David Wood --- .../rustc_error_messages/locales/en-US/lint.ftl | 8 ++++++++ compiler/rustc_lint/src/builtin.rs | 15 +++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 34ce4b9d96751..bf69db38b42eb 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -358,3 +358,11 @@ lint-builtin-unstable-features = unstable feature lint-builtin-unreachable-pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility .help = or consider exporting it for use by other crates + +lint-builtin-type-alias-bounds-help = use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases + +lint-builtin-type-alias-where-clause = where clauses are not enforced in type aliases + .suggestion = the clause will not be checked when the type alias is used, and should be removed + +lint-builtin-type-alias-generic-bounds = bounds on generic parameters are not enforced in type aliases + .suggestion = the bound will not be checked when the type alias is used, and should be removed diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6c21936629170..0c109763d50e5 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1499,11 +1499,7 @@ impl TypeAliasBounds { impl Visitor<'_> for WalkAssocTypes<'_> { fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) { if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help( - span, - "use fully disambiguated paths (i.e., `::Assoc`) to refer to \ - associated types in type aliases", - ); + self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help); } intravisit::walk_qpath(self, qpath, id, span) } @@ -1547,11 +1543,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { let mut suggested_changing_assoc_types = false; if !where_spans.is_empty() { cx.lint(TYPE_ALIAS_BOUNDS, |lint| { - let mut err = lint.build("where clauses are not enforced in type aliases"); + let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause); err.set_span(where_spans); err.span_suggestion( type_alias_generics.where_clause_span, - "the clause will not be checked when the type alias is used, and should be removed", + fluent::lint::suggestion, "", Applicability::MachineApplicable, ); @@ -1565,11 +1561,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { if !inline_spans.is_empty() { cx.lint(TYPE_ALIAS_BOUNDS, |lint| { - let mut err = - lint.build("bounds on generic parameters are not enforced in type aliases"); + let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds); err.set_span(inline_spans); err.multipart_suggestion( - "the bound will not be checked when the type alias is used, and should be removed", + fluent::lint::suggestion, inline_sugg, Applicability::MachineApplicable, ); From 3c9bda5b20139844a1b31960f9fc13349a52048d Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:09:25 +0100 Subject: [PATCH 46/60] lint: port trivial bounds diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 10 ++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index bf69db38b42eb..cdc3cab8fee99 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -366,3 +366,5 @@ lint-builtin-type-alias-where-clause = where clauses are not enforced in type al lint-builtin-type-alias-generic-bounds = bounds on generic parameters are not enforced in type aliases .suggestion = the bound will not be checked when the type alias is used, and should be removed + +lint-builtin-trivial-bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 0c109763d50e5..1098fd8c14c60 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1671,12 +1671,10 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { }; if predicate.is_global() { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { - lint.build(&format!( - "{} bound {} does not depend on any type \ - or lifetime parameters", - predicate_kind_name, predicate - )) - .emit(); + lint.build(fluent::lint::builtin_trivial_bounds) + .set_arg("predicate_kind_name", predicate_kind_name) + .set_arg("predicate", predicate) + .emit(); }); } } From 3a498a74362f05164c6301d4b10ece4f75180302 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:16:03 +0100 Subject: [PATCH 47/60] lint: port `...` range pattern diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/builtin.rs | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index cdc3cab8fee99..7310f4c241fbe 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -368,3 +368,6 @@ lint-builtin-type-alias-generic-bounds = bounds on generic parameters are not en .suggestion = the bound will not be checked when the type alias is used, and should be removed lint-builtin-trivial-bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters + +lint-builtin-ellipsis-inclusive-range-patterns = `...` range patterns are deprecated + .suggestion = use `..=` for an inclusive range diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 1098fd8c14c60..7c9e9a31e1e18 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1775,8 +1775,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { }; if let Some((start, end, join)) = endpoints { - let msg = "`...` range patterns are deprecated"; - let suggestion = "use `..=` for an inclusive range"; + let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns; + let suggestion = fluent::lint::suggestion; if parenthesise { self.node_id = Some(pat.id); let end = expr_to_string(&end); @@ -1785,8 +1785,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { None => format!("&(..={})", end), }; if join.edition() >= Edition::Edition2021 { - let mut err = - rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); + let mut err = cx.sess().struct_span_err_with_code( + pat.span, + msg, + rustc_errors::error_code!(E0783), + ); err.span_suggestion( pat.span, suggestion, @@ -1809,8 +1812,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } else { let replace = "..="; if join.edition() >= Edition::Edition2021 { - let mut err = - rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); + let mut err = cx.sess().struct_span_err_with_code( + pat.span, + msg, + rustc_errors::error_code!(E0783), + ); err.span_suggestion_short( join, suggestion, From 10f2d3f566d4271ee95b9b1ae51dbf51b4aa1707 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:20:10 +0100 Subject: [PATCH 48/60] lint: port test items diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 7310f4c241fbe..4d1aca61105b0 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -371,3 +371,5 @@ lint-builtin-trivial-bounds = {$predicate_kind_name} bound {$predicate} does not lint-builtin-ellipsis-inclusive-range-patterns = `...` range patterns are deprecated .suggestion = use `..=` for an inclusive range + +lint-builtin-unnameable-test-items = cannot test inner items diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 7c9e9a31e1e18..df30ea9370867 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1915,7 +1915,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { let attrs = cx.tcx.hir().attrs(it.hir_id()); if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| { - lint.build("cannot test inner items").emit(); + lint.build(fluent::lint::builtin_unnameable_test_items).emit(); }); } } From 10676418fa01d4f0ae8a34c57e4a71d7cd4c7cf2 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:28:02 +0100 Subject: [PATCH 49/60] lint: port keyword idents diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_errors/src/diagnostic.rs | 8 +++++++- compiler/rustc_lint/src/builtin.rs | 6 ++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 4d1aca61105b0..134ee43f02231 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -373,3 +373,6 @@ lint-builtin-ellipsis-inclusive-range-patterns = `...` range patterns are deprec .suggestion = use `..=` for an inclusive range lint-builtin-unnameable-test-items = cannot test inner items + +lint-builtin-keyword-idents = `{$kw}` is a keyword in the {$next} edition + .suggestion = you can use a raw identifier to stay compatible diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 03e90b7b0d961..fc619ad54cf92 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -8,7 +8,7 @@ use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{edition::Edition, Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; @@ -115,6 +115,12 @@ impl IntoDiagnosticArg for String { } } +impl IntoDiagnosticArg for Edition { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + impl IntoDiagnosticArg for Symbol { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { self.to_ident_string().into_diagnostic_arg() diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index df30ea9370867..a3ebc547544f1 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2033,10 +2033,12 @@ impl KeywordIdents { } cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| { - lint.build(&format!("`{}` is a keyword in the {} edition", ident, next_edition)) + lint.build(fluent::lint::builtin_keyword_idents) + .set_arg("kw", ident.clone()) + .set_arg("next", next_edition) .span_suggestion( ident.span, - "you can use a raw identifier to stay compatible", + fluent::lint::suggestion, format!("r#{}", ident), Applicability::MachineApplicable, ) From acea23e79617fd269dfa2ef3caca9225e87e9452 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:32:38 +0100 Subject: [PATCH 50/60] lint: port explicit outlives diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 6 ++++++ compiler/rustc_lint/src/builtin.rs | 9 +++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 134ee43f02231..d21e3de1c4fb4 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -376,3 +376,9 @@ lint-builtin-unnameable-test-items = cannot test inner items lint-builtin-keyword-idents = `{$kw}` is a keyword in the {$next} edition .suggestion = you can use a raw identifier to stay compatible + +lint-builtin-explicit-outlives = outlives requirements can be inferred + .suggestion = remove {$count -> + [one] this bound + *[other] these bounds + } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a3ebc547544f1..1205b1c5e4688 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2288,13 +2288,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { if !lint_spans.is_empty() { cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| { - lint.build("outlives requirements can be inferred") + lint.build(fluent::lint::builtin_explicit_outlives) + .set_arg("count", bound_count) .multipart_suggestion( - if bound_count == 1 { - "remove this bound" - } else { - "remove these bounds" - }, + fluent::lint::suggestion, lint_spans .into_iter() .map(|span| (span, String::new())) From bd8fe82138ba24f1c9f27bb64bf4269aabf9d54a Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:40:11 +0100 Subject: [PATCH 51/60] lint: port incomplete features diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 4 ++++ compiler/rustc_errors/src/diagnostic.rs | 6 ++++++ compiler/rustc_lint/src/builtin.rs | 19 +++++-------------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index d21e3de1c4fb4..a1ad032099992 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -382,3 +382,7 @@ lint-builtin-explicit-outlives = outlives requirements can be inferred [one] this bound *[other] these bounds } + +lint-builtin-incomplete-features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes + .note = see issue #{$n} for more information + .help = consider using `min_{$name}` instead, which is more stable and complete diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index fc619ad54cf92..3043ae827f92f 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -115,6 +115,12 @@ impl IntoDiagnosticArg for String { } } +impl IntoDiagnosticArg for std::num::NonZeroU32 { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + impl IntoDiagnosticArg for Edition { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { DiagnosticArgValue::Str(Cow::Owned(self.to_string())) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 1205b1c5e4688..035cd358a9155 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2347,23 +2347,14 @@ impl EarlyLintPass for IncompleteFeatures { .filter(|(&name, _)| features.incomplete(name)) .for_each(|(&name, &span)| { cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| { - let mut builder = lint.build(&format!( - "the feature `{}` is incomplete and may not be safe to use \ - and/or cause compiler crashes", - name, - )); + let mut builder = lint.build(fluent::lint::builtin_incomplete_features); + builder.set_arg("name", name); if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) { - builder.note(&format!( - "see issue #{} \ - for more information", - n, n, - )); + builder.set_arg("n", n); + builder.note(fluent::lint::note); } if HAS_MIN_FEATURES.contains(&name) { - builder.help(&format!( - "consider using `min_{}` instead, which is more stable and complete", - name, - )); + builder.help(fluent::lint::help); } builder.emit(); }) From 157cbbca04fa60b48bb5fec3221ff00d727a0abf Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 14:50:35 +0100 Subject: [PATCH 52/60] lint: add todo for invalid value diagnostics Signed-off-by: David Wood --- compiler/rustc_lint/src/builtin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 035cd358a9155..2751c5d6e58b4 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2595,6 +2595,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { if let Some((msg, span)) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) { + // FIXME(davidtwco): make translatable cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| { let mut err = lint.build(&format!( "the type `{}` does not permit {}", From 2e563a4a3e040f30dc89b53abdfc874a695452a8 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 15:08:34 +0100 Subject: [PATCH 53/60] lint: port clashing extern diagnostics Signed-off-by: David Wood --- .../locales/en-US/lint.ftl | 7 ++++++ compiler/rustc_lint/src/builtin.rs | 24 ++++++++----------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index a1ad032099992..087c70d94aa1b 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -386,3 +386,10 @@ lint-builtin-explicit-outlives = outlives requirements can be inferred lint-builtin-incomplete-features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes .note = see issue #{$n} for more information .help = consider using `min_{$name}` instead, which is more stable and complete + +lint-builtin-clashing-extern-same-name = `{$this_fi}` redeclared with a different signature + .previous-decl-label = `{$orig}` previously declared here + .mismatch-label = this signature doesn't match the previous declaration +lint-builtin-clashing-extern-diff-name = `{$this_fi}` redeclares `{$orig}` with a different signature + .previous-decl-label = `{$orig}` previously declared here + .mismatch-label = this signature doesn't match the previous declaration diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 2751c5d6e58b4..4317f71912711 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2972,23 +2972,19 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { let mut found_str = DiagnosticStyledString::new(); found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); - lint.build(&format!( - "`{}` redeclare{} with a different signature", - this_fi.ident.name, - if orig.get_name() == this_fi.ident.name { - "d".to_string() - } else { - format!("s `{}`", orig.get_name()) - } - )) + lint.build(if orig.get_name() == this_fi.ident.name { + fluent::lint::builtin_clashing_extern_same_name + } else { + fluent::lint::builtin_clashing_extern_diff_name + }) + .set_arg("this_fi", this_fi.ident.name) + .set_arg("orig", orig.get_name()) .span_label( get_relevant_span(orig_fi), - &format!("`{}` previously declared here", orig.get_name()), - ) - .span_label( - get_relevant_span(this_fi), - "this signature doesn't match the previous declaration", + fluent::lint::previous_decl_label, ) + .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label) + // FIXME(davidtwco): translatable expected/found .note_expected_found(&"", expected_str, &"", found_str) .emit(); }, From 5524ca1a1d5784911753ea07f716af6710d87b38 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 15:12:35 +0100 Subject: [PATCH 54/60] lint: port deref nullptr diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 +++ compiler/rustc_lint/src/builtin.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 087c70d94aa1b..6a7d8a75450a8 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -393,3 +393,6 @@ lint-builtin-clashing-extern-same-name = `{$this_fi}` redeclared with a differen lint-builtin-clashing-extern-diff-name = `{$this_fi}` redeclares `{$orig}` with a different signature .previous-decl-label = `{$orig}` previously declared here .mismatch-label = this signature doesn't match the previous declaration + +lint-builtin-deref-nullptr = dereferencing a null pointer + .label = this code causes undefined behavior when executed diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 4317f71912711..6197c240f54b4 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3068,8 +3068,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { if is_null_ptr(cx, expr_deref) { cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| { - let mut err = lint.build("dereferencing a null pointer"); - err.span_label(expr.span, "this code causes undefined behavior when executed"); + let mut err = lint.build(fluent::lint::builtin_deref_nullptr); + err.span_label(expr.span, fluent::lint::label); err.emit(); }); } From fedd4c63f8d49699b7844490503a63c9207d851a Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 Jun 2022 15:16:49 +0100 Subject: [PATCH 55/60] lint: port asm labels diagnostics Signed-off-by: David Wood --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 ++ compiler/rustc_lint/src/builtin.rs | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 6a7d8a75450a8..e7e07093c0324 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -396,3 +396,5 @@ lint-builtin-clashing-extern-diff-name = `{$this_fi}` redeclares `{$orig}` with lint-builtin-deref-nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed + +lint-builtin-asm-labels = avoid using named labels in inline assembly diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6197c240f54b4..428af513498a8 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3182,9 +3182,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { NAMED_ASM_LABELS, Some(target_spans), |diag| { - let mut err = - diag.build("avoid using named labels in inline assembly"); - err.emit(); + diag.build(fluent::lint::builtin_asm_labels).emit(); }, BuiltinLintDiagnostics::NamedAsmLabel( "only local labels of the form `:` should be used in inline asm" From 9ff6c77d2f65ea57bbe7d656cf81071645823b90 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 29 Jun 2022 09:21:44 +0100 Subject: [PATCH 56/60] tests: avoid inadvertent diffs in diag derive test In the diagnostic derive test, a "the following other types implement trait" diagnostic is output which lists rustc types that implement `IntoDiagnosticArg`. As the output of this test can change due to new internal compiler types like implementing `IntoDiagnosticArg`, it can start failing without indicating a problem to be fixed - so normalize that output away. Signed-off-by: David Wood --- .../session-diagnostic/diagnostic-derive.rs | 2 + .../diagnostic-derive.stderr | 114 +++++++++--------- 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 7bec1897fa53e..18283c19cb42c 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -1,6 +1,8 @@ // check-fail // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] +// normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr" + // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, // changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler // the test is just ignored on stable and beta: diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 0d9690e1f5a99..9e2e34e4bec81 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -1,5 +1,5 @@ error: `#[derive(SessionDiagnostic)]` can only be used on structs - --> $DIR/diagnostic-derive.rs:37:1 + --> $DIR/diagnostic-derive.rs:39:1 | LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | @@ -10,13 +10,13 @@ LL | | } | |_^ error: `#[error = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:46:1 + --> $DIR/diagnostic-derive.rs:48:1 | LL | #[error = "E0123"] | ^^^^^^^^^^^^^^^^^^ error: `#[nonsense(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:51:1 + --> $DIR/diagnostic-derive.rs:53:1 | LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] = help: only `error`, `warning`, `help` and `note` are valid attributes error: diagnostic kind not specified - --> $DIR/diagnostic-derive.rs:51:1 + --> $DIR/diagnostic-derive.rs:53:1 | LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | | @@ -36,7 +36,7 @@ LL | | struct InvalidStructAttr {} = help: use the `#[error(...)]` attribute to create an error error: `#[error("...")]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:58:9 + --> $DIR/diagnostic-derive.rs:60:9 | LL | #[error("E0123")] | ^^^^^^^ @@ -44,7 +44,7 @@ LL | #[error("E0123")] = help: first argument of the attribute should be the diagnostic slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:58:1 + --> $DIR/diagnostic-derive.rs:60:1 | LL | / #[error("E0123")] LL | | @@ -55,7 +55,7 @@ LL | | struct InvalidLitNestedAttr {} = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: `#[error(nonsense(...))]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:69:9 + --> $DIR/diagnostic-derive.rs:71:9 | LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")] | ^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")] = help: first argument of the attribute should be the diagnostic slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:69:1 + --> $DIR/diagnostic-derive.rs:71:1 | LL | / #[error(nonsense("foo"), code = "E0123", slug = "foo")] LL | | @@ -74,7 +74,7 @@ LL | | struct InvalidNestedStructAttr1 {} = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: `#[error(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:75:9 + --> $DIR/diagnostic-derive.rs:77:9 | LL | #[error(nonsense = "...", code = "E0123", slug = "foo")] | ^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | #[error(nonsense = "...", code = "E0123", slug = "foo")] = help: first argument of the attribute should be the diagnostic slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:75:1 + --> $DIR/diagnostic-derive.rs:77:1 | LL | / #[error(nonsense = "...", code = "E0123", slug = "foo")] LL | | @@ -93,7 +93,7 @@ LL | | struct InvalidNestedStructAttr2 {} = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: `#[error(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:81:9 + --> $DIR/diagnostic-derive.rs:83:9 | LL | #[error(nonsense = 4, code = "E0123", slug = "foo")] | ^^^^^^^^^^^^ @@ -101,7 +101,7 @@ LL | #[error(nonsense = 4, code = "E0123", slug = "foo")] = help: first argument of the attribute should be the diagnostic slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:81:1 + --> $DIR/diagnostic-derive.rs:83:1 | LL | / #[error(nonsense = 4, code = "E0123", slug = "foo")] LL | | @@ -112,7 +112,7 @@ LL | | struct InvalidNestedStructAttr3 {} = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: `#[error(slug = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:87:59 + --> $DIR/diagnostic-derive.rs:89:59 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")] | ^^^^^^^^^^^^ @@ -120,103 +120,103 @@ LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")] = help: only `code` is a valid nested attributes following the slug error: `#[suggestion = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:94:5 + --> $DIR/diagnostic-derive.rs:96:5 | LL | #[suggestion = "bar"] | ^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:101:1 + --> $DIR/diagnostic-derive.rs:103:1 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:100:1 + --> $DIR/diagnostic-derive.rs:102:1 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:101:1 + --> $DIR/diagnostic-derive.rs:103:1 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:100:1 + --> $DIR/diagnostic-derive.rs:102:1 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:101:50 + --> $DIR/diagnostic-derive.rs:103:50 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:100:50 + --> $DIR/diagnostic-derive.rs:102:50 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:109:1 + --> $DIR/diagnostic-derive.rs:111:1 | LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:108:1 + --> $DIR/diagnostic-derive.rs:110:1 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:109:1 + --> $DIR/diagnostic-derive.rs:111:1 | LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:108:1 + --> $DIR/diagnostic-derive.rs:110:1 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:109:52 + --> $DIR/diagnostic-derive.rs:111:52 | LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:108:50 + --> $DIR/diagnostic-derive.rs:110:50 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:116:66 + --> $DIR/diagnostic-derive.rs:118:66 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] | ^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:116:50 + --> $DIR/diagnostic-derive.rs:118:50 | LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")] | ^^^^^^^ error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:121:43 + --> $DIR/diagnostic-derive.rs:123:43 | LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic kind not specified - --> $DIR/diagnostic-derive.rs:126:1 + --> $DIR/diagnostic-derive.rs:128:1 | LL | struct KindNotProvided {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -224,7 +224,7 @@ LL | struct KindNotProvided {} = help: use the `#[error(...)]` attribute to create an error error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:129:1 + --> $DIR/diagnostic-derive.rs:131:1 | LL | / #[error(code = "E0456")] LL | | @@ -234,13 +234,13 @@ LL | | struct SlugNotProvided {} = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]` error: the `#[primary_span]` attribute can only be applied to fields of type `Span` - --> $DIR/diagnostic-derive.rs:140:5 + --> $DIR/diagnostic-derive.rs:142:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: `#[nonsense]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:148:5 + --> $DIR/diagnostic-derive.rs:150:5 | LL | #[nonsense] | ^^^^^^^^^^^ @@ -248,19 +248,19 @@ LL | #[nonsense] = help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes error: the `#[label(...)]` attribute can only be applied to fields of type `Span` - --> $DIR/diagnostic-derive.rs:165:5 + --> $DIR/diagnostic-derive.rs:167:5 | LL | #[label(typeck::label)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/diagnostic-derive.rs:173:45 + --> $DIR/diagnostic-derive.rs:175:45 | LL | #[suggestion(typeck::suggestion, code = "{name}")] | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/diagnostic-derive.rs:178:16 + --> $DIR/diagnostic-derive.rs:180:16 | LL | #[derive(SessionDiagnostic)] | - ^ expected `'}'` in format string @@ -271,7 +271,7 @@ LL | #[derive(SessionDiagnostic)] = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/diagnostic-derive.rs:188:15 + --> $DIR/diagnostic-derive.rs:190:15 | LL | #[derive(SessionDiagnostic)] | ^ unmatched `}` in format string @@ -280,13 +280,13 @@ LL | #[derive(SessionDiagnostic)] = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `#[label(...)]` attribute can only be applied to fields of type `Span` - --> $DIR/diagnostic-derive.rs:208:5 + --> $DIR/diagnostic-derive.rs:210:5 | LL | #[label(typeck::label)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: `#[suggestion(nonsense = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:233:18 + --> $DIR/diagnostic-derive.rs:235:18 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^^^^^^^^^ @@ -294,7 +294,7 @@ LL | #[suggestion(nonsense = "bar")] = help: only `message`, `code` and `applicability` are valid field attributes error: `#[suggestion(msg = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:241:18 + --> $DIR/diagnostic-derive.rs:243:18 | LL | #[suggestion(msg = "bar")] | ^^^^^^^^^^^ @@ -302,7 +302,7 @@ LL | #[suggestion(msg = "bar")] = help: only `message`, `code` and `applicability` are valid field attributes error: wrong field type for suggestion - --> $DIR/diagnostic-derive.rs:263:5 + --> $DIR/diagnostic-derive.rs:265:5 | LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | | @@ -312,7 +312,7 @@ LL | | suggestion: Applicability, = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` error: type of field annotated with `#[suggestion(...)]` contains more than one `Span` - --> $DIR/diagnostic-derive.rs:278:5 + --> $DIR/diagnostic-derive.rs:280:5 | LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | | @@ -320,7 +320,7 @@ LL | | suggestion: (Span, Span, Applicability), | |___________________________________________^ error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability - --> $DIR/diagnostic-derive.rs:286:5 + --> $DIR/diagnostic-derive.rs:288:5 | LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | | @@ -328,72 +328,66 @@ LL | | suggestion: (Applicability, Applicability, Span), | |____________________________________________________^ error: `#[label = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:294:5 + --> $DIR/diagnostic-derive.rs:296:5 | LL | #[label = "bar"] | ^^^^^^^^^^^^^^^^ error: applicability cannot be set in both the field and attribute - --> $DIR/diagnostic-derive.rs:445:52 + --> $DIR/diagnostic-derive.rs:447:52 | LL | #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/diagnostic-derive.rs:453:52 + --> $DIR/diagnostic-derive.rs:455:52 | LL | #[suggestion(typeck::suggestion, code = "...", applicability = "batman")] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[label(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:516:5 + --> $DIR/diagnostic-derive.rs:518:5 | LL | #[label(typeck::label, foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[label(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:524:5 + --> $DIR/diagnostic-derive.rs:526:5 | LL | #[label(typeck::label, foo = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[label(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:532:5 + --> $DIR/diagnostic-derive.rs:534:5 | LL | #[label(typeck::label, foo("..."))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:51:3 + --> $DIR/diagnostic-derive.rs:53:3 | LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")] | ^^^^^^^^ error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:148:7 + --> $DIR/diagnostic-derive.rs:150:7 | LL | #[nonsense] | ^^^^^^^^ error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent` - --> $DIR/diagnostic-derive.rs:64:9 + --> $DIR/diagnostic-derive.rs:66:9 | LL | #[error(nonsense, code = "E0123")] | ^^^^^^^^ not found in `rustc_errors::fluent` error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive.rs:338:10 + --> $DIR/diagnostic-derive.rs:340:10 | LL | #[derive(SessionDiagnostic)] | ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello` | - = help: the following other types implement trait `IntoDiagnosticArg`: - &'a str - Ident - String - Symbol - rustc_middle::ty::Ty<'tcx> - usize + = help: normalized in stderr note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:538:19 | From 83f22885ae9fe7116f97efd7f7df9b6a719d7e6f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 1 Jul 2022 12:13:46 -0700 Subject: [PATCH 57/60] Improve click behavior of the source code mobile full-screen "sidebar" On desktop, if you open the source code sidebar, it stays open even when you move from page to page. It used to do the same thing on mobile, but I think that's stupid. Since the file list fills the entire screen on mobile, and you can't really do anything with the currently selected file other than dismiss the "sidebar" to look at it, it's safe to assume that anybody who clicks a file in that list probably wants the list to go away so they can see it. --- src/librustdoc/html/static/css/rustdoc.css | 10 +++++++++ .../html/static/js/source-script.js | 11 ++++++++-- src/librustdoc/html/static/js/storage.js | 5 +++++ .../sidebar-source-code-display.goml | 22 +++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 532b98d9bb9f6..04492da82265d 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1683,6 +1683,11 @@ details.rustdoc-toggle[open] > summary.hideme::after { /* Media Queries */ +/* +WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY; +If you update this line, then you also need to update the line with the same warning +in storage.js plus the media query with (max-width: 700px) +*/ @media (min-width: 701px) { /* In case there is no documentation before a code block, we need to add some margin at the top to prevent an overlay between the "collapse toggle" and the information tooltip. @@ -1703,6 +1708,11 @@ details.rustdoc-toggle[open] > summary.hideme::after { } } +/* +WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY +If you update this line, then you also need to update the line with the same warning +in storage.js plus the media query with (min-width: 701px) +*/ @media (max-width: 700px) { /* When linking to an item with an `id` (for instance, by clicking a link in the sidebar, or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index acb1d8d7b5c8d..586c14c33a3ba 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -12,6 +12,12 @@ const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value; let oldScrollPosition = 0; +function closeSidebarIfMobile() { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + updateLocalStorage("source-sidebar-show", "false"); + } +} + function createDirEntry(elem, parent, fullPath, hasFoundFile) { const name = document.createElement("div"); name.className = "name"; @@ -48,6 +54,7 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) { const file = document.createElement("a"); file.innerText = file_text; file.href = rootPath + "src/" + fullPath + file_text + ".html"; + file.addEventListener("click", closeSidebarIfMobile); const w = window.location.href.split("#")[0]; if (!hasFoundFile && w === file.href) { file.className = "selected"; @@ -66,7 +73,7 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) { function toggleSidebar() { const child = this.children[0]; if (child.innerText === ">") { - if (window.innerWidth < 701) { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { // This is to keep the scroll position on mobile. oldScrollPosition = window.scrollY; document.body.style.position = "fixed"; @@ -76,7 +83,7 @@ function toggleSidebar() { child.innerText = "<"; updateLocalStorage("source-sidebar-show", "true"); } else { - if (window.innerWidth < 701) { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { // This is to keep the scroll position on mobile. document.body.style.position = ""; document.body.style.top = ""; diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 1c4c88344888c..0c5389d45e5b7 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -9,6 +9,11 @@ const darkThemes = ["dark", "ayu"]; window.currentTheme = document.getElementById("themeStyle"); window.mainTheme = document.getElementById("mainThemeStyle"); +// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY +// If you update this line, then you also need to update the two media queries with the same +// warning in rustdoc.css +window.RUSTDOC_MOBILE_BREAKPOINT = 701; + const settingsDataset = (function() { const settingsElement = document.getElementById("default-settings"); if (settingsElement === null) { diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml index c441f84a82135..7728bfd025ff2 100644 --- a/src/test/rustdoc-gui/sidebar-source-code-display.goml +++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml @@ -18,6 +18,16 @@ click: "#sidebar-toggle" // Because of the transition CSS, we check by using `wait-for-css` instead of `assert-css`. wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1}) +// We now check that opening the sidebar and clicking a link will leave it open. +// The behavior here on desktop is different than the behavior on mobile, +// but since the sidebar doesn't fill the entire screen here, it makes sense to have the +// sidebar stay resident. +wait-for-css: (".sidebar", {"width": "300px"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} +click: ".sidebar a.selected" +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} + // Now we check the display of the sidebar items. show-text: true @@ -152,3 +162,15 @@ click: "#sidebar-toggle" wait-for-css: (".sidebar", {"width": "0px"}) // The "scrollTop" property should be the same. assert-window-property: {"pageYOffset": "2519"} + +// We now check that opening the sidebar and clicking a link will close it. +// The behavior here on mobile is different than the behavior on desktop, +// but common sense dictates that if you have a list of files that fills the entire screen, and +// you click one of them, you probably want to actually see the file's contents, and not just +// make it the current selection. +click: "#sidebar-toggle" +wait-for-css: (".sidebar", {"width": "500px"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} +click: ".sidebar a.selected" +goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +assert-local-storage: {"rustdoc-source-sidebar-show": "false"} From 6e2c49f7eddb4c09e17653760965b69a3dc97fb0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 2 Jul 2022 10:41:46 -0700 Subject: [PATCH 58/60] rustdoc: add gui test case ensuring source sidebar doesn't spontaneously open --- src/test/rustdoc-gui/sidebar-source-code-display.goml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml index 7728bfd025ff2..8d13246a63f80 100644 --- a/src/test/rustdoc-gui/sidebar-source-code-display.goml +++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml @@ -26,6 +26,7 @@ wait-for-css: (".sidebar", {"width": "300px"}) assert-local-storage: {"rustdoc-source-sidebar-show": "true"} click: ".sidebar a.selected" goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +wait-for-css: (".sidebar", {"width": "300px"}) assert-local-storage: {"rustdoc-source-sidebar-show": "true"} // Now we check the display of the sidebar items. @@ -169,8 +170,16 @@ assert-window-property: {"pageYOffset": "2519"} // you click one of them, you probably want to actually see the file's contents, and not just // make it the current selection. click: "#sidebar-toggle" -wait-for-css: (".sidebar", {"width": "500px"}) +wait-for-css: ("#source-sidebar", {"visibility": "visible"}) assert-local-storage: {"rustdoc-source-sidebar-show": "true"} click: ".sidebar a.selected" goto: file://|DOC_PATH|/src/test_docs/lib.rs.html +wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "false"} +// Resize back to desktop size, to check that the sidebar doesn't spontaneously open. +size: (1000, 1000) +wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) assert-local-storage: {"rustdoc-source-sidebar-show": "false"} +click: "#sidebar-toggle" +wait-for-css: ("#source-sidebar", {"visibility": "visible"}) +assert-local-storage: {"rustdoc-source-sidebar-show": "true"} From ce9e834b6b4ce59f14a19d2d0a774f61f81eab4c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 3 Jul 2022 20:23:30 +0200 Subject: [PATCH 59/60] Remove FIXME from rustdoc intra-doc test --- src/test/rustdoc/intra-doc/pub-use.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs index 0c70cdee91462..8a998496cf56b 100644 --- a/src/test/rustdoc/intra-doc/pub-use.rs +++ b/src/test/rustdoc/intra-doc/pub-use.rs @@ -5,21 +5,11 @@ extern crate inner; /// [mod@std::env] [g] - -// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports. -// Until then, comment out the `htmldocck` test. -// This test still does something; namely check that no incorrect errors are emitted when -// documenting the re-export. - // @has outer/index.html -// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env" -// @ has - '//a[@href="fn.f.html"]' "g" +// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env" +// @has - '//a[@href="fn.f.html"]' "g" pub use f as g; -// FIXME: same as above -/// [std::env] -extern crate self as _; - // Make sure the documentation is actually correct by documenting an inlined re-export /// [mod@std::env] // @has outer/fn.f.html From 170b173a3b1c3d3be5b979285238aae13cdee8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 5 Jul 2022 09:29:11 +0300 Subject: [PATCH 60/60] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index b74e96f509baf..75b22326dad19 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit b74e96f509baf0be70281c55f14cb18fefbc6b22 +Subproject commit 75b22326dad1914c22484ab6672de5cae94f7457