1
Fork 0

Auto merge of #98925 - Dylan-DPC:rollup-9185c9y, r=Dylan-DPC

Rollup of 5 pull requests

Successful merges:

 - #97712 (ptr::copy and ptr::swap are doing untyped copies)
 - #98624 (lints: mostly translatable diagnostics)
 - #98776 (rustdoc: improve click behavior of the source code mobile full-screen "sidebar")
 - #98856 (Remove FIXME from rustdoc intra-doc test)
 - #98913 (⬆️ rust-analyzer)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-07-05 12:17:26 +00:00
commit 54f79babae
39 changed files with 1223 additions and 737 deletions

View file

@ -0,0 +1,400 @@
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
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.
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}
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
lint-tykind-kind = usage of `ty::TyKind::<kind>`
.suggestion = try using `ty::<kind>` 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
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
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
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
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
.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
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
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
lint-redundant-semicolons =
unnecessary trailing {$multiple ->
[true] semicolons
*[false] semicolon
}
.suggestion = remove {$multiple ->
[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
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
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`
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
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
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}
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`
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
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
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
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
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
lint-builtin-type-alias-bounds-help = use fully disambiguated paths (i.e., `<T as Trait>::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
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
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
}
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} <https://github.com/rust-lang/rust/issues/{$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
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

View file

@ -31,11 +31,12 @@ pub use unic_langid::{langid, LanguageIdentifier};
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
fluent_messages! { 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", parser => "../locales/en-US/parser.ftl",
privacy => "../locales/en-US/privacy.ftl", privacy => "../locales/en-US/privacy.ftl",
typeck => "../locales/en-US/typeck.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}; pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};

View file

@ -8,7 +8,7 @@ use rustc_error_messages::FluentValue;
use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::symbol::{Ident, Symbol}; 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::borrow::Cow;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@ -39,12 +39,94 @@ pub trait IntoDiagnosticArg {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; 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 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()))
}
}
impl IntoDiagnosticArg for u128 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}
impl IntoDiagnosticArg for String { impl IntoDiagnosticArg for String {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self)) DiagnosticArgValue::Str(Cow::Owned(self))
} }
} }
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()))
}
}
impl IntoDiagnosticArg for Symbol { impl IntoDiagnosticArg for Symbol {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.to_ident_string().into_diagnostic_arg() self.to_ident_string().into_diagnostic_arg()

View file

@ -529,7 +529,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
applicability: Applicability, applicability: Applicability,
) -> &mut Self); ) -> &mut Self);
forward!(pub fn set_primary_message(&mut self, msg: impl Into<String>) -> &mut Self); forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self); forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
forward!(pub fn set_arg( forward!(pub fn set_arg(

View file

@ -1,5 +1,5 @@
use crate::{LateContext, LateLintPass, LintContext}; use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability; use rustc_errors::{fluent, Applicability};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment}; 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"), _ => bug!("array type coerced to something other than array or slice"),
}; };
cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| { cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| {
let mut diag = lint.build(&format!( let mut diag = lint.build(fluent::lint::array_into_iter);
"this method call resolves to `<&{} as IntoIterator>::into_iter` \ diag.set_arg("target", target);
(due to backwards compatibility), \
but will resolve to <{} as IntoIterator>::into_iter in Rust 2021",
target, target,
));
diag.span_suggestion( diag.span_suggestion(
call.ident.span, call.ident.span,
"use `.iter()` instead of `.into_iter()` to avoid ambiguity", fluent::lint::use_iter_suggestion,
"iter", "iter",
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
if self.for_expr_span == expr.span { if self.for_expr_span == expr.span {
diag.span_suggestion( diag.span_suggestion(
receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), 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, Applicability::MaybeIncorrect,
); );
} else if receiver_ty.is_array() { } else if receiver_ty.is_array() {
diag.multipart_suggestion( 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![ vec![
(expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()), (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, Applicability::MaybeIncorrect,
); );

View file

@ -31,7 +31,9 @@ use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, Diagnostic, DiagnosticStyledString, MultiSpan}; use rustc_errors::{
fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
};
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@ -99,13 +101,12 @@ impl EarlyLintPass for WhileTrue {
if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind { if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
if let ast::LitKind::Bool(true) = lit.kind { if let ast::LitKind::Bool(true) = lit.kind {
if !lit.span.from_expansion() { if !lit.span.from_expansion() {
let msg = "denote infinite loops with `loop { ... }`";
let condition_span = e.span.with_hi(cond.span.hi()); let condition_span = e.span.with_hi(cond.span.hi());
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
lint.build(msg) lint.build(fluent::lint::builtin_while_true)
.span_suggestion_short( .span_suggestion_short(
condition_span, condition_span,
"use `loop`", fluent::lint::suggestion,
format!( format!(
"{}loop", "{}loop",
label.map_or_else(String::new, |label| format!( label.map_or_else(String::new, |label| format!(
@ -156,7 +157,7 @@ impl BoxPointers {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if leaf_ty.is_box() { if leaf_ty.is_box() {
cx.struct_span_lint(BOX_POINTERS, span, |lint| { 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();
}); });
} }
} }
@ -257,26 +258,26 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
== Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results())) == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
{ {
cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| { 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 { let binding = match binding_annot {
hir::BindingAnnotation::Unannotated => None, hir::BindingAnnotation::Unannotated => None,
hir::BindingAnnotation::Mutable => Some("mut"), hir::BindingAnnotation::Mutable => Some("mut"),
hir::BindingAnnotation::Ref => Some("ref"), hir::BindingAnnotation::Ref => Some("ref"),
hir::BindingAnnotation::RefMut => Some("ref mut"), hir::BindingAnnotation::RefMut => Some("ref mut"),
}; };
let ident = if let Some(binding) = binding { let suggested_ident = if let Some(binding) = binding {
format!("{} {}", binding, ident) format!("{} {}", binding, ident)
} else { } else {
ident.to_string() ident.to_string()
}; };
err.span_suggestion( lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
fieldpat.span, .set_arg("ident", ident.clone())
"use shorthand field pattern", .span_suggestion(
ident, fieldpat.span,
Applicability::MachineApplicable, fluent::lint::suggestion,
); suggested_ident,
err.emit(); Applicability::MachineApplicable,
)
.emit();
}); });
} }
} }
@ -327,26 +328,25 @@ impl UnsafeCode {
cx.struct_span_lint(UNSAFE_CODE, span, decorate); 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| { self.report_unsafe(cx, span, |lint| {
lint.build(msg) lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
.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();
}) })
} }
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| { self.report_unsafe(cx, span, |lint| {
lint.build(msg) lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
.note(
"the program's behavior with overridden link sections on items is unpredictable \
and Rust cannot provide guarantees when you manually override them",
)
.emit();
}) })
} }
} }
@ -355,12 +355,7 @@ impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if attr.has_name(sym::allow_internal_unsafe) { if attr.has_name(sym::allow_internal_unsafe) {
self.report_unsafe(cx, attr.span, |lint| { self.report_unsafe(cx, attr.span, |lint| {
lint.build( lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
"`allow_internal_unsafe` allows defining \
macros using unsafe without triggering \
the `unsafe_code` lint at their call site",
)
.emit();
}); });
} }
} }
@ -370,7 +365,7 @@ impl EarlyLintPass for UnsafeCode {
// Don't warn about generated blocks; that'll just pollute the output. // Don't warn about generated blocks; that'll just pollute the output.
if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) { if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
self.report_unsafe(cx, blk.span, |lint| { self.report_unsafe(cx, blk.span, |lint| {
lint.build("usage of an `unsafe` block").emit(); lint.build(fluent::lint::builtin_unsafe_block).emit();
}); });
} }
} }
@ -380,12 +375,12 @@ impl EarlyLintPass for UnsafeCode {
match it.kind { match it.kind {
ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| { .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 ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| { .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(..) => { ast::ItemKind::Fn(..) => {
@ -393,7 +388,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name( self.report_overridden_symbol_name(
cx, cx,
attr.span, attr.span,
"declaration of a `no_mangle` function", fluent::lint::builtin_no_mangle_fn,
); );
} }
@ -401,7 +396,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name( self.report_overridden_symbol_name(
cx, cx,
attr.span, attr.span,
"declaration of a function with `export_name`", fluent::lint::builtin_export_name_fn,
); );
} }
@ -409,7 +404,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_section( self.report_overridden_symbol_section(
cx, cx,
attr.span, attr.span,
"declaration of a function with `link_section`", fluent::lint::builtin_link_section_fn,
); );
} }
} }
@ -419,7 +414,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name( self.report_overridden_symbol_name(
cx, cx,
attr.span, attr.span,
"declaration of a `no_mangle` static", fluent::lint::builtin_no_mangle_static,
); );
} }
@ -427,7 +422,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name( self.report_overridden_symbol_name(
cx, cx,
attr.span, attr.span,
"declaration of a static with `export_name`", fluent::lint::builtin_export_name_static,
); );
} }
@ -435,7 +430,7 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_section( self.report_overridden_symbol_section(
cx, cx,
attr.span, attr.span,
"declaration of a static with `link_section`", fluent::lint::builtin_link_section_static,
); );
} }
} }
@ -450,14 +445,14 @@ impl EarlyLintPass for UnsafeCode {
self.report_overridden_symbol_name( self.report_overridden_symbol_name(
cx, cx,
attr.span, 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) { if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
self.report_overridden_symbol_name( self.report_overridden_symbol_name(
cx, cx,
attr.span, attr.span,
"declaration of a method with `export_name`", fluent::lint::builtin_export_name_method,
); );
} }
} }
@ -475,9 +470,9 @@ impl EarlyLintPass for UnsafeCode {
{ {
let msg = match ctxt { let msg = match ctxt {
FnCtxt::Foreign => return, FnCtxt::Foreign => return,
FnCtxt::Free => "declaration of an `unsafe` function", FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method", FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
FnCtxt::Assoc(_) => "implementation of an `unsafe` method", FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
}; };
self.report_unsafe(cx, span, |lint| { self.report_unsafe(cx, span, |lint| {
lint.build(msg).emit(); lint.build(msg).emit();
@ -587,7 +582,10 @@ impl MissingDoc {
MISSING_DOCS, MISSING_DOCS,
cx.tcx.sess.source_map().guess_head_span(sp), cx.tcx.sess.source_map().guess_head_span(sp),
|lint| { |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();
}, },
); );
} }
@ -783,11 +781,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
.is_ok() .is_ok()
{ {
cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| { cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
lint.build( lint.build(fluent::lint::builtin_missing_copy_impl).emit();
"type could implement `Copy`; consider adding `impl \
Copy`",
)
.emit();
}) })
} }
} }
@ -863,12 +857,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
if !self.impling_types.as_ref().unwrap().contains(&item.def_id) { if !self.impling_types.as_ref().unwrap().contains(&item.def_id) {
cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| { cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
lint.build(&format!( lint.build(fluent::lint::builtin_missing_debug_impl)
"type does not implement `{}`; consider adding `#[derive(Debug)]` \ .set_arg("debug", cx.tcx.def_path_str(debug))
or a manual implementation", .emit();
cx.tcx.def_path_str(debug)
))
.emit();
}); });
} }
} }
@ -946,18 +937,14 @@ impl EarlyLintPass for AnonymousParameters {
("<type>", Applicability::HasPlaceholders) ("<type>", Applicability::HasPlaceholders)
}; };
lint.build( lint.build(fluent::lint::builtin_anonymous_params)
"anonymous parameters are deprecated and will be \ .span_suggestion(
removed in the next edition", arg.pat.span,
) fluent::lint::suggestion,
.span_suggestion( format!("_: {}", ty_snip),
arg.pat.span, appl,
"try naming the parameter or explicitly \ )
ignoring it", .emit();
format!("_: {}", ty_snip),
appl,
)
.emit();
}) })
} }
} }
@ -982,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 { impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
for BuiltinAttribute { name, gate, .. } in &self.depr_attrs { for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
@ -1011,17 +980,38 @@ impl EarlyLintPass for DeprecatedAttr {
_, _,
) = gate ) = gate
{ {
let msg = cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link); // FIXME(davidtwco) translatable deprecated attr
lint_deprecated_attr(cx, attr, &msg, suggestion); 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; return;
} }
} }
if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) { 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); cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); lint.build(fluent::lint::builtin_deprecated_attr_used)
lint_deprecated_attr(cx, attr, &msg, None); .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();
});
} }
} }
} }
@ -1049,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) { if is_doc_comment || attr.has_name(sym::doc) {
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
let mut err = lint.build("unused doc comment"); let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
err.span_label( err.set_arg("kind", node_kind);
node_span, err.span_label(node_span, fluent::lint::label);
format!("rustdoc does not generate documentation for {}", node_kind),
);
match attr.kind { match attr.kind {
AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => { AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
err.help("use `//` for a plain comment"); err.help(fluent::lint::plain_help);
} }
AttrKind::DocComment(CommentKind::Block, _) => { AttrKind::DocComment(CommentKind::Block, _) => {
err.help("use `/* */` for a plain comment"); err.help(fluent::lint::block_help);
} }
} }
err.emit(); err.emit();
@ -1178,10 +1166,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
GenericParamKind::Lifetime { .. } => {} GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| { 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( .span_suggestion_short(
no_mangle_attr.span, no_mangle_attr.span,
"remove this attribute", fluent::lint::suggestion,
"", "",
// Use of `#[no_mangle]` suggests FFI intent; correct // Use of `#[no_mangle]` suggests FFI intent; correct
// fix may be to monomorphize source by hand // fix may be to monomorphize source by hand
@ -1205,8 +1193,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
// Const items do not refer to a particular location in memory, and therefore // Const items do not refer to a particular location in memory, and therefore
// don't have anything to attach a symbol to // don't have anything to attach a symbol to
cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| { 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(fluent::lint::builtin_const_no_mangle);
let mut err = lint.build(msg);
// account for "pub const" (#45562) // account for "pub const" (#45562)
let start = cx let start = cx
@ -1220,7 +1207,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5)); let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
err.span_suggestion( err.span_suggestion(
const_span, const_span,
"try a static value", fluent::lint::suggestion,
"pub static", "pub static",
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@ -1285,10 +1272,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
{ {
if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { 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| { cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
lint.build(msg).emit(); lint.build(fluent::lint::builtin_mutable_transmutes).emit();
}); });
} }
} }
@ -1338,7 +1323,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
if let Some(items) = attr.meta_item_list() { if let Some(items) = attr.meta_item_list() {
for item in items { for item in items {
cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| { cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
lint.build("unstable feature").emit(); lint.build(fluent::lint::builtin_unstable_features).emit();
}); });
} }
} }
@ -1400,16 +1385,17 @@ impl UnreachablePub {
} }
let def_span = cx.tcx.sess.source_map().guess_head_span(span); let def_span = cx.tcx.sess.source_map().guess_head_span(span);
cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| { 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( err.span_suggestion(
vis_span, vis_span,
"consider restricting its visibility", fluent::lint::suggestion,
"pub(crate)", "pub(crate)",
applicability, applicability,
); );
if exportable { if exportable {
err.help("or consider exporting it for use by other crates"); err.help(fluent::lint::help);
} }
err.emit(); err.emit();
}); });
@ -1513,11 +1499,7 @@ impl TypeAliasBounds {
impl Visitor<'_> for WalkAssocTypes<'_> { impl Visitor<'_> for WalkAssocTypes<'_> {
fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) { fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
if TypeAliasBounds::is_type_variable_assoc(qpath) { if TypeAliasBounds::is_type_variable_assoc(qpath) {
self.err.span_help( self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
span,
"use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to \
associated types in type aliases",
);
} }
intravisit::walk_qpath(self, qpath, id, span) intravisit::walk_qpath(self, qpath, id, span)
} }
@ -1561,11 +1543,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
let mut suggested_changing_assoc_types = false; let mut suggested_changing_assoc_types = false;
if !where_spans.is_empty() { if !where_spans.is_empty() {
cx.lint(TYPE_ALIAS_BOUNDS, |lint| { 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.set_span(where_spans);
err.span_suggestion( err.span_suggestion(
type_alias_generics.where_clause_span, 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, Applicability::MachineApplicable,
); );
@ -1579,11 +1561,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
if !inline_spans.is_empty() { if !inline_spans.is_empty() {
cx.lint(TYPE_ALIAS_BOUNDS, |lint| { cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
let mut err = let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
lint.build("bounds on generic parameters are not enforced in type aliases");
err.set_span(inline_spans); err.set_span(inline_spans);
err.multipart_suggestion( err.multipart_suggestion(
"the bound will not be checked when the type alias is used, and should be removed", fluent::lint::suggestion,
inline_sugg, inline_sugg,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@ -1690,12 +1671,10 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
}; };
if predicate.is_global() { if predicate.is_global() {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
lint.build(&format!( lint.build(fluent::lint::builtin_trivial_bounds)
"{} bound {} does not depend on any type \ .set_arg("predicate_kind_name", predicate_kind_name)
or lifetime parameters", .set_arg("predicate", predicate)
predicate_kind_name, predicate .emit();
))
.emit();
}); });
} }
} }
@ -1796,8 +1775,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}; };
if let Some((start, end, join)) = endpoints { if let Some((start, end, join)) = endpoints {
let msg = "`...` range patterns are deprecated"; let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
let suggestion = "use `..=` for an inclusive range"; let suggestion = fluent::lint::suggestion;
if parenthesise { if parenthesise {
self.node_id = Some(pat.id); self.node_id = Some(pat.id);
let end = expr_to_string(&end); let end = expr_to_string(&end);
@ -1806,8 +1785,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
None => format!("&(..={})", end), None => format!("&(..={})", end),
}; };
if join.edition() >= Edition::Edition2021 { if join.edition() >= Edition::Edition2021 {
let mut err = let mut err = cx.sess().struct_span_err_with_code(
rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); pat.span,
msg,
rustc_errors::error_code!(E0783),
);
err.span_suggestion( err.span_suggestion(
pat.span, pat.span,
suggestion, suggestion,
@ -1830,8 +1812,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
} else { } else {
let replace = "..="; let replace = "..=";
if join.edition() >= Edition::Edition2021 { if join.edition() >= Edition::Edition2021 {
let mut err = let mut err = cx.sess().struct_span_err_with_code(
rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,); pat.span,
msg,
rustc_errors::error_code!(E0783),
);
err.span_suggestion_short( err.span_suggestion_short(
join, join,
suggestion, suggestion,
@ -1930,7 +1915,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
let attrs = cx.tcx.hir().attrs(it.hir_id()); let attrs = cx.tcx.hir().attrs(it.hir_id());
if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| { 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();
}); });
} }
} }
@ -2048,10 +2033,12 @@ impl KeywordIdents {
} }
cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| { 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( .span_suggestion(
ident.span, ident.span,
"you can use a raw identifier to stay compatible", fluent::lint::suggestion,
format!("r#{}", ident), format!("r#{}", ident),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
@ -2301,13 +2288,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
if !lint_spans.is_empty() { if !lint_spans.is_empty() {
cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| { 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( .multipart_suggestion(
if bound_count == 1 { fluent::lint::suggestion,
"remove this bound"
} else {
"remove these bounds"
},
lint_spans lint_spans
.into_iter() .into_iter()
.map(|span| (span, String::new())) .map(|span| (span, String::new()))
@ -2363,23 +2347,14 @@ impl EarlyLintPass for IncompleteFeatures {
.filter(|(&name, _)| features.incomplete(name)) .filter(|(&name, _)| features.incomplete(name))
.for_each(|(&name, &span)| { .for_each(|(&name, &span)| {
cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| { cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
let mut builder = lint.build(&format!( let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
"the feature `{}` is incomplete and may not be safe to use \ builder.set_arg("name", name);
and/or cause compiler crashes",
name,
));
if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) { if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
builder.note(&format!( builder.set_arg("n", n);
"see issue #{} <https://github.com/rust-lang/rust/issues/{}> \ builder.note(fluent::lint::note);
for more information",
n, n,
));
} }
if HAS_MIN_FEATURES.contains(&name) { if HAS_MIN_FEATURES.contains(&name) {
builder.help(&format!( builder.help(fluent::lint::help);
"consider using `min_{}` instead, which is more stable and complete",
name,
));
} }
builder.emit(); builder.emit();
}) })
@ -2620,6 +2595,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
if let Some((msg, span)) = if let Some((msg, span)) =
with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) 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| { cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
let mut err = lint.build(&format!( let mut err = lint.build(&format!(
"the type `{}` does not permit {}", "the type `{}` does not permit {}",
@ -2996,23 +2972,19 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
let mut found_str = DiagnosticStyledString::new(); let mut found_str = DiagnosticStyledString::new();
found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
lint.build(&format!( lint.build(if orig.get_name() == this_fi.ident.name {
"`{}` redeclare{} with a different signature", fluent::lint::builtin_clashing_extern_same_name
this_fi.ident.name, } else {
if orig.get_name() == this_fi.ident.name { fluent::lint::builtin_clashing_extern_diff_name
"d".to_string() })
} else { .set_arg("this_fi", this_fi.ident.name)
format!("s `{}`", orig.get_name()) .set_arg("orig", orig.get_name())
}
))
.span_label( .span_label(
get_relevant_span(orig_fi), get_relevant_span(orig_fi),
&format!("`{}` previously declared here", orig.get_name()), fluent::lint::previous_decl_label,
)
.span_label(
get_relevant_span(this_fi),
"this signature doesn't match the previous declaration",
) )
.span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
// FIXME(davidtwco): translatable expected/found
.note_expected_found(&"", expected_str, &"", found_str) .note_expected_found(&"", expected_str, &"", found_str)
.emit(); .emit();
}, },
@ -3096,8 +3068,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind { if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
if is_null_ptr(cx, expr_deref) { if is_null_ptr(cx, expr_deref) {
cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| { cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
let mut err = lint.build("dereferencing a null pointer"); let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
err.span_label(expr.span, "this code causes undefined behavior when executed"); err.span_label(expr.span, fluent::lint::label);
err.emit(); err.emit();
}); });
} }
@ -3210,9 +3182,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
NAMED_ASM_LABELS, NAMED_ASM_LABELS,
Some(target_spans), Some(target_spans),
|diag| { |diag| {
let mut err = diag.build(fluent::lint::builtin_asm_labels).emit();
diag.build("avoid using named labels in inline assembly");
err.emit();
}, },
BuiltinLintDiagnostics::NamedAsmLabel( BuiltinLintDiagnostics::NamedAsmLabel(
"only local labels of the form `<number>:` should be used in inline asm" "only local labels of the form `<number>:` should be used in inline asm"

View file

@ -1,4 +1,5 @@
use crate::{context::LintContext, LateContext, LateLintPass}; use crate::{context::LintContext, LateContext, LateLintPass};
use rustc_errors::fluent;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty::{fold::TypeFoldable, Ty}; use rustc_middle::ty::{fold::TypeFoldable, Ty};
use rustc_span::{symbol::sym, Span}; use rustc_span::{symbol::sym, Span};
@ -51,19 +52,9 @@ fn enforce_mem_discriminant(
if is_non_enum(ty_param) { if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| { cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
builder builder
.build( .build(fluent::lint::enum_intrinsics_mem_discriminant)
"the return value of `mem::discriminant` is \ .set_arg("ty_param", ty_param)
unspecified when called with a non-enum type", .span_note(args_span, fluent::lint::note)
)
.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,
),
)
.emit(); .emit();
}); });
} }
@ -74,16 +65,9 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp
if is_non_enum(ty_param) { if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| { cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
builder builder
.build( .build(fluent::lint::enum_intrinsics_mem_variant)
"the return value of `mem::variant_count` is \ .set_arg("ty_param", ty_param)
unspecified when called with a non-enum type", .note(fluent::lint::note)
)
.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,
))
.emit(); .emit();
}); });
} }

View file

@ -1,4 +1,5 @@
use crate::builtin; use crate::builtin;
use rustc_errors::fluent;
use rustc_hir::HirId; use rustc_hir::HirId;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::{lint::LintExpectation, ty::TyCtxt}; use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
@ -43,13 +44,13 @@ fn emit_unfulfilled_expectation_lint(
hir_id, hir_id,
expectation.emission_span, expectation.emission_span,
|diag| { |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 { if let Some(rationale) = expectation.reason {
diag.note(rationale.as_str()); diag.note(rationale.as_str());
} }
if expectation.is_unfulfilled_lint_expectations { 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(); diag.emit();

View file

@ -1,7 +1,7 @@
use crate::{EarlyContext, EarlyLintPass, LintContext}; use crate::{EarlyContext, EarlyLintPass, LintContext};
use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS}; use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_errors::{Applicability, SuggestionStyle}; use rustc_errors::{fluent, Applicability, SuggestionStyle};
use rustc_span::{BytePos, Span, Symbol}; use rustc_span::{BytePos, Span, Symbol};
declare_lint! { declare_lint! {
@ -61,41 +61,25 @@ impl HiddenUnicodeCodepoints {
.collect(); .collect();
cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| { cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
let mut err = lint.build(&format!( let mut err = lint.build(fluent::lint::hidden_unicode_codepoints);
"unicode codepoint changing visible direction of text present in {}", err.set_arg("label", label);
label err.set_arg("count", spans.len());
)); err.span_label(span, fluent::lint::label);
let (an, s) = match spans.len() { err.note(fluent::lint::note);
1 => ("an ", ""),
_ => ("", "s"),
};
err.span_label(
span,
&format!(
"this {} contains {}invisible unicode text flow control codepoint{}",
label, an, s,
),
);
if point_at_inner_spans { if point_at_inner_spans {
for (c, span) in &spans { for (c, span) in &spans {
err.span_label(*span, format!("{:?}", c)); 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() { if point_at_inner_spans && !spans.is_empty() {
err.multipart_suggestion_with_style( 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(), spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
SuggestionStyle::HideCodeAlways, SuggestionStyle::HideCodeAlways,
); );
err.multipart_suggestion( err.multipart_suggestion(
"if you want to keep them but make them visible in your source code, you can \ fluent::lint::suggestion_escape,
escape them",
spans spans
.into_iter() .into_iter()
.map(|(c, span)| { .map(|(c, span)| {
@ -109,16 +93,16 @@ impl HiddenUnicodeCodepoints {
// FIXME: in other suggestions we've reversed the inner spans of doc comments. We // 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 // should do the same here to provide the same good suggestions as we do for
// literals above. // literals above.
err.note("if their presence wasn't intentional, you can remove them"); err.set_arg(
err.note(&format!( "escaped",
"if you want to keep them but make them visible in your source code, you can \
escape them: {}",
spans spans
.into_iter() .into_iter()
.map(|(c, _)| { format!("{:?}", c) }) .map(|(c, _)| format!("{:?}", c))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", "), .join(", "),
)); );
err.note(fluent::lint::suggestion_remove);
err.note(fluent::lint::no_suggestion_note_escape);
} }
err.emit(); err.emit();
}); });

View file

@ -3,7 +3,7 @@
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_errors::Applicability; use rustc_errors::{fluent, Applicability};
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
@ -36,13 +36,10 @@ impl LateLintPass<'_> for DefaultHashTypes {
_ => return, _ => return,
}; };
cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| { cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
let msg = format!( lint.build(fluent::lint::default_hash_types)
"prefer `{}` over `{}`, it has better performance", .set_arg("preferred", replace)
replace, .set_arg("used", cx.tcx.item_name(def_id))
cx.tcx.item_name(def_id) .note(fluent::lint::note)
);
lint.build(&msg)
.note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
.emit(); .emit();
}); });
} }
@ -99,12 +96,9 @@ impl LateLintPass<'_> for QueryStability {
let def_id = instance.def_id(); let def_id = instance.def_id();
if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| { cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
let msg = format!( lint.build(fluent::lint::query_instability)
"using `{}` can result in unstable query results", .set_arg("query", cx.tcx.item_name(def_id))
cx.tcx.item_name(def_id) .note(fluent::lint::note)
);
lint.build(&msg)
.note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
.emit(); .emit();
}) })
} }
@ -146,10 +140,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
); );
cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| { cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
lint.build("usage of `ty::TyKind::<kind>`") lint.build(fluent::lint::tykind_kind)
.span_suggestion( .span_suggestion(
span, span,
"try using `ty::<kind>` directly", fluent::lint::suggestion,
"ty", "ty",
Applicability::MaybeIncorrect, // ty maybe needs an import Applicability::MaybeIncorrect, // ty maybe needs an import
) )
@ -175,10 +169,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
if let QPath::TypeRelative(qpath_ty, ..) = qpath if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id && qpath_ty.hir_id == ty.hir_id
{ {
lint.build("usage of `ty::TyKind::<kind>`") lint.build(fluent::lint::tykind_kind)
.span_suggestion( .span_suggestion(
path.span, path.span,
"try using `ty::<kind>` directly", fluent::lint::suggestion,
"ty", "ty",
Applicability::MaybeIncorrect, // ty maybe needs an import Applicability::MaybeIncorrect, // ty maybe needs an import
) )
@ -193,10 +187,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
if let QPath::TypeRelative(qpath_ty, ..) = qpath if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id && qpath_ty.hir_id == ty.hir_id
{ {
lint.build("usage of `ty::TyKind::<kind>`") lint.build(fluent::lint::tykind_kind)
.span_suggestion( .span_suggestion(
path.span, path.span,
"try using `ty::<kind>` directly", fluent::lint::suggestion,
"ty", "ty",
Applicability::MaybeIncorrect, // ty maybe needs an import Applicability::MaybeIncorrect, // ty maybe needs an import
) )
@ -213,10 +207,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
if let QPath::TypeRelative(qpath_ty, ..) = qpath if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id && qpath_ty.hir_id == ty.hir_id
{ {
lint.build("usage of `ty::TyKind::<kind>`") lint.build(fluent::lint::tykind_kind)
.span_suggestion( .span_suggestion(
path.span, path.span,
"try using `ty::<kind>` directly", fluent::lint::suggestion,
"ty", "ty",
Applicability::MaybeIncorrect, // ty maybe needs an import Applicability::MaybeIncorrect, // ty maybe needs an import
) )
@ -226,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) { } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
if path.segments.len() > 1 { if path.segments.len() > 1 {
cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| { 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( .span_suggestion(
path.span, path.span,
"try importing it and using it unqualified", fluent::lint::suggestion,
t, t,
// The import probably needs to be changed // The import probably needs to be changed
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
@ -330,8 +325,8 @@ impl EarlyLintPass for LintPassImpl {
LINT_PASS_IMPL_WITHOUT_MACRO, LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span, lint_pass.path.span,
|lint| { |lint| {
lint.build("implementing `LintPass` by hand") lint.build(fluent::lint::lintpass_by_hand)
.help("try using `declare_lint_pass!` or `impl_lint_pass!` instead") .help(fluent::lint::help)
.emit(); .emit();
}, },
) )
@ -371,13 +366,10 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
return; return;
} }
cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| { cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
lint.build(&format!( lint.build(fluent::lint::non_existant_doc_keyword)
"Found non-existing keyword `{}` used in \ .set_arg("keyword", v)
`#[doc(keyword = \"...\")]`", .help(fluent::lint::help)
v, .emit();
))
.help("only existing keywords are allowed in core/std")
.emit();
}); });
} }
} }
@ -431,8 +423,7 @@ impl LateLintPass<'_> for Diagnostics {
debug!(?found_impl); debug!(?found_impl);
if !found_impl { if !found_impl {
cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| { cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
lint.build("diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls") lint.build(fluent::lint::diag_out_of_impl).emit();
.emit();
}) })
} }
@ -450,7 +441,7 @@ impl LateLintPass<'_> for Diagnostics {
debug!(?found_diagnostic_message); debug!(?found_diagnostic_message);
if !found_diagnostic_message { if !found_diagnostic_message {
cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| { 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();
}) })
} }
} }

View file

@ -521,7 +521,7 @@ impl<'s> LintLevelsBuilder<'s> {
src, src,
Some(sp.into()), Some(sp.into()),
|lint| { |lint| {
let mut err = lint.build(&msg); let mut err = lint.build(msg);
if let Some(new_name) = &renamed { if let Some(new_name) = &renamed {
err.span_suggestion( err.span_suggestion(
sp, sp,
@ -548,7 +548,7 @@ impl<'s> LintLevelsBuilder<'s> {
} else { } else {
name.to_string() 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 { if let Some(suggestion) = suggestion {
db.span_suggestion( db.span_suggestion(
sp, sp,

View file

@ -1,6 +1,7 @@
use crate::LateContext; use crate::LateContext;
use crate::LateLintPass; use crate::LateLintPass;
use crate::LintContext; use crate::LintContext;
use rustc_errors::fluent;
use rustc_hir::{Expr, ExprKind, PathSegment}; use rustc_hir::{Expr, ExprKind, PathSegment};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::{symbol::sym, ExpnKind, Span}; 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 let ty::Adt(adt, _) = substs.type_at(0).kind() {
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| { cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
let mut diag = diag diag.build(fluent::lint::cstring_ptr)
.build("getting the inner pointer of a temporary `CString`"); .span_label(as_ptr_span, fluent::lint::as_ptr_label)
diag.span_label(as_ptr_span, "this pointer will be invalid"); .span_label(unwrap.span, fluent::lint::unwrap_label)
diag.span_label( .note(fluent::lint::note)
unwrap.span, .help(fluent::lint::help)
"this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime", .emit();
);
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();
}); });
} }
} }

View file

@ -1,6 +1,7 @@
use crate::{EarlyContext, EarlyLintPass, LintContext}; use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::fluent;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
declare_lint! { declare_lint! {
@ -180,13 +181,13 @@ impl EarlyLintPass for NonAsciiIdents {
} }
has_non_ascii_idents = true; has_non_ascii_idents = true;
cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| { 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 if check_uncommon_codepoints
&& !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed) && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
{ {
cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| { 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)| { .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
if !*existing_is_ascii || !is_ascii { if !*existing_is_ascii || !is_ascii {
cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| { cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
lint.build(&format!( lint.build(fluent::lint::confusable_identifier_pair)
"identifier pair considered confusable between `{}` and `{}`", .set_arg("existing_sym", *existing_symbol)
existing_symbol, symbol .set_arg("sym", symbol)
)) .span_label(*existing_span, fluent::lint::label)
.span_label( .emit();
*existing_span,
"this is where the previous identifier occurred",
)
.emit();
}); });
} }
if *existing_is_ascii && !is_ascii { if *existing_is_ascii && !is_ascii {
@ -326,18 +323,20 @@ impl EarlyLintPass for NonAsciiIdents {
for ((sp, ch_list), script_set) in lint_reports { for ((sp, ch_list), script_set) in lint_reports {
cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| { cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
let message = format!( let mut includes = String::new();
"the usage of Script Group `{}` in this crate consists solely of mixed script confusables",
script_set);
let mut note = "the usage includes ".to_string();
for (idx, ch) in ch_list.into_iter().enumerate() { for (idx, ch) in ch_list.into_iter().enumerate() {
if idx != 0 { if idx != 0 {
note += ", "; includes += ", ";
} }
let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
note += &char_info; includes += &char_info;
} }
lint.build(&message).note(&note).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();
}); });
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{LateContext, LateLintPass, LintContext}; use crate::{LateContext, LateLintPass, LintContext};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_errors::{pluralize, Applicability}; use rustc_errors::{fluent, Applicability};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::lint::in_external_macro; 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| { cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
let mut l = lint.build("panic message is not a string literal"); let mut l = lint.build(fluent::lint::non_fmt_panic);
l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol)); l.set_arg("name", symbol);
l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>"); l.note(fluent::lint::note);
l.note(fluent::lint::more_info_note);
if !is_arg_inside_call(arg_span, span) { if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from. // No clue where this argument is coming from.
l.emit(); 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)) { if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`. // 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) { if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
l.multipart_suggestion( l.multipart_suggestion(
"remove the `format!(..)` macro call", fluent::lint::supports_fmt_suggestion,
vec![ vec![
(arg_span.until(open.shrink_to_hi()), "".into()), (arg_span.until(open.shrink_to_hi()), "".into()),
(close.until(arg_span.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 (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { let display = is_str
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
}) == Some(true); infcx
let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() .may_apply()
}) == Some(true); }) == 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) (display, debug)
}); });
@ -175,17 +182,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
if suggest_display { if suggest_display {
l.span_suggestion_verbose( l.span_suggestion_verbose(
arg_span.shrink_to_lo(), arg_span.shrink_to_lo(),
"add a \"{}\" format string to Display the message", fluent::lint::display_suggestion,
"\"{}\", ", "\"{}\", ",
fmt_applicability, fmt_applicability,
); );
} else if suggest_debug { } else if suggest_debug {
l.set_arg("ty", ty);
l.span_suggestion_verbose( l.span_suggestion_verbose(
arg_span.shrink_to_lo(), arg_span.shrink_to_lo(),
&format!( fluent::lint::debug_suggestion,
"add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
ty,
),
"\"{:?}\", ", "\"{:?}\", ",
fmt_applicability, 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 suggest_panic_any {
if let Some((open, close, del)) = find_delimiters(cx, span) { if let Some((open, close, del)) = find_delimiters(cx, span) {
l.set_arg("already_suggested", suggest_display || suggest_debug);
l.multipart_suggestion( l.multipart_suggestion(
&format!( fluent::lint::panic_suggestion,
"{}use std::panic::panic_any instead",
if suggest_display || suggest_debug {
"or "
} else {
""
},
),
if del == '(' { if del == '(' {
vec![(span.until(open), "std::panic::panic_any".into())] vec![(span.until(open), "std::panic::panic_any".into())]
} else { } else {
@ -260,21 +259,19 @@ fn check_panic_str<'tcx>(
.collect(), .collect(),
}; };
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| { cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
let mut l = lint.build(match n_arguments { let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
1 => "panic message contains an unused formatting placeholder", l.set_arg("count", n_arguments);
_ => "panic message contains unused formatting placeholders", l.note(fluent::lint::note);
});
l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
if is_arg_inside_call(arg.span, span) { if is_arg_inside_call(arg.span, span) {
l.span_suggestion( l.span_suggestion(
arg.span.shrink_to_hi(), arg.span.shrink_to_hi(),
&format!("add the missing argument{}", pluralize!(n_arguments)), fluent::lint::add_args_suggestion,
", ...", ", ...",
Applicability::HasPlaceholders, Applicability::HasPlaceholders,
); );
l.span_suggestion( l.span_suggestion(
arg.span.shrink_to_lo(), arg.span.shrink_to_lo(),
"or add a \"{}\" format string to use the message literally", fluent::lint::add_fmt_suggestion,
"\"{}\", ", "\"{}\", ",
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@ -289,17 +286,15 @@ fn check_panic_str<'tcx>(
.map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 })) .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
.collect() .collect()
}); });
let msg = match &brace_spans { let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
Some(v) if v.len() == 1 => "panic message contains a brace",
_ => "panic message contains braces",
};
cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| { cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
let mut l = lint.build(msg); let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
l.note("this message is not used as a format string, but will be in Rust 2021"); l.set_arg("count", count);
l.note(fluent::lint::note);
if is_arg_inside_call(arg.span, span) { if is_arg_inside_call(arg.span, span) {
l.span_suggestion( l.span_suggestion(
arg.span.shrink_to_lo(), arg.span.shrink_to_lo(),
"add a \"{}\" format string to use the message literally", fluent::lint::suggestion,
"\"{}\", ", "\"{}\", ",
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );

View file

@ -1,7 +1,7 @@
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_errors::Applicability; use rustc_errors::{fluent, Applicability};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
@ -137,22 +137,23 @@ impl NonCamelCaseTypes {
if !is_camel_case(name) { if !is_camel_case(name) {
cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| { 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(fluent::lint::non_camel_case_type);
let mut err = lint.build(&msg);
let cc = to_camel_case(name); let cc = to_camel_case(name);
// We cannot provide meaningful suggestions // We cannot provide meaningful suggestions
// if the characters are in the category of "Lowercase Letter". // if the characters are in the category of "Lowercase Letter".
if *name != cc { if *name != cc {
err.span_suggestion( err.span_suggestion(
ident.span, ident.span,
"convert the identifier to upper camel case", fluent::lint::suggestion,
to_camel_case(name), to_camel_case(name),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } 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(); err.emit();
}) })
} }
@ -281,11 +282,10 @@ impl NonSnakeCase {
if !is_snake_case(name) { if !is_snake_case(name) {
cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| { cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| {
let sc = NonSnakeCase::to_snake_case(name); let sc = NonSnakeCase::to_snake_case(name);
let msg = format!("{} `{}` should have a snake case name", sort, name); let mut err = lint.build(fluent::lint::non_snake_case);
let mut err = lint.build(&msg);
// We cannot provide meaningful suggestions // We cannot provide meaningful suggestions
// if the characters are in the category of "Uppercase Letter". // 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 // 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. // name provided via the command line.
if !ident.span.is_dummy() { if !ident.span.is_dummy() {
@ -295,13 +295,13 @@ impl NonSnakeCase {
// Instead, recommend renaming the identifier entirely or, if permitted, // Instead, recommend renaming the identifier entirely or, if permitted,
// escaping it to create a raw identifier. // escaping it to create a raw identifier.
if sc_ident.name.can_be_raw() { 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 { } else {
err.note(&format!("`{}` cannot be used as a raw identifier", sc)); err.note(fluent::lint::cannot_convert_note);
("rename the identifier", String::new()) (fluent::lint::rename_suggestion, String::new())
} }
} else { } else {
("convert the identifier to snake case", sc) (fluent::lint::convert_suggestion, sc.clone())
}; };
err.span_suggestion( err.span_suggestion(
@ -311,12 +311,15 @@ impl NonSnakeCase {
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } else {
err.help(&format!("convert the identifier to snake case: `{}`", sc)); err.help(fluent::lint::help);
} }
} else { } 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(); err.emit();
}); });
} }
@ -488,21 +491,22 @@ impl NonUpperCaseGlobals {
if name.chars().any(|c| c.is_lowercase()) { if name.chars().any(|c| c.is_lowercase()) {
cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| { cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
let uc = NonSnakeCase::to_snake_case(&name).to_uppercase(); let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
let mut err = let mut err = lint.build(fluent::lint::non_upper_case_global);
lint.build(&format!("{} `{}` should have an upper case name", sort, name));
// We cannot provide meaningful suggestions // We cannot provide meaningful suggestions
// if the characters are in the category of "Lowercase Letter". // if the characters are in the category of "Lowercase Letter".
if *name != uc { if *name != uc {
err.span_suggestion( err.span_suggestion(
ident.span, ident.span,
"convert the identifier to upper case", fluent::lint::suggestion,
uc, uc,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else { } 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(); err.emit();
}) })
} }

View file

@ -2,6 +2,7 @@ use crate::context::LintContext;
use crate::rustc_middle::ty::TypeFoldable; use crate::rustc_middle::ty::TypeFoldable;
use crate::LateContext; use crate::LateContext;
use crate::LateLintPass; use crate::LateLintPass;
use rustc_errors::fluent;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_middle::ty; use rustc_middle::ty;
@ -80,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
) { ) {
return; return;
} }
let method = &call.ident.name;
let receiver = &elements[0]; let receiver = &elements[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver); let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
@ -90,19 +90,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
return; return;
} }
let expr_span = expr.span; 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()); let span = expr_span.with_lo(receiver.span.hi());
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
let method = &call.ident.name; lint.build(fluent::lint::noop_method_call)
let message = .set_arg("method", call.ident.name)
format!("call to `.{}()` on a reference in this situation does nothing", &method,); .set_arg("receiver_ty", receiver_ty)
lint.build(&message).span_label(span, "unnecessary method call").note(&note).emit(); .span_label(span, fluent::lint::label)
.note(fluent::lint::note)
.emit();
}); });
} }
} }

View file

@ -1,5 +1,5 @@
use crate::{LateContext, LateLintPass, LintContext}; use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability; use rustc_errors::{fluent, Applicability};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::{GenericArg, PathSegment, QPath, TyKind}; 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) { if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| { 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( .span_suggestion(
ty.span, ty.span,
"try passing by value", fluent::lint::suggestion,
t, t,
// Changing type of function argument // Changing type of function argument
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,

View file

@ -1,6 +1,6 @@
use crate::{EarlyContext, EarlyLintPass, LintContext}; use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast::{Block, StmtKind}; use rustc_ast::{Block, StmtKind};
use rustc_errors::Applicability; use rustc_errors::{fluent, Applicability};
use rustc_span::Span; use rustc_span::Span;
declare_lint! { 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| { cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
let (msg, rem) = if multiple { lint.build(fluent::lint::redundant_semicolons)
("unnecessary trailing semicolons", "remove these semicolons") .set_arg("multiple", multiple)
} else { .span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect)
("unnecessary trailing semicolon", "remove this semicolon") .emit();
};
lint.build(msg).span_suggestion(span, rem, "", Applicability::MaybeIncorrect).emit();
}); });
} }
} }

View file

@ -1,6 +1,7 @@
use crate::LateContext; use crate::LateContext;
use crate::LateLintPass; use crate::LateLintPass;
use crate::LintContext; use crate::LintContext;
use rustc_errors::fluent;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_span::symbol::sym; 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 { let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
return return
}; };
let msg = format!( lint.build(fluent::lint::drop_trait_constraints)
"bounds on `{}` are most likely incorrect, consider instead \ .set_arg("predicate", predicate)
using `{}` to detect whether a type can be trivially dropped", .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
predicate, .emit();
cx.tcx.def_path_str(needs_drop)
);
lint.build(&msg).emit();
}); });
} }
} }
@ -126,12 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
return return
}; };
let msg = format!( lint.build(fluent::lint::drop_glue)
"types that do not implement `Drop` can still have drop glue, consider \ .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
instead using `{}` to detect whether a type is trivially dropped", .emit();
cx.tcx.def_path_str(needs_drop)
);
lint.build(&msg).emit();
}); });
} }
} }

View file

@ -2,7 +2,7 @@ use crate::{LateContext, LateLintPass, LintContext};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::{fluent, Applicability, DiagnosticMessage};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
@ -139,7 +139,8 @@ fn lint_overflowing_range_endpoint<'tcx>(
// overflowing and only by 1. // overflowing and only by 1.
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max { if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| { 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) { if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
use ast::{LitIntType, LitKind}; use ast::{LitIntType, LitKind};
// We need to preserve the literal's suffix, // 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); let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
err.span_suggestion( err.span_suggestion(
parent_expr.span, parent_expr.span,
"use an inclusive range instead", fluent::lint::suggestion,
suggestion, suggestion,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@ -229,38 +230,35 @@ fn report_bin_hex_error(
(t.name_str(), actually.to_string()) (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 negative {
// If the value is negative, // If the value is negative,
// emits a note about the value itself, apart from the literal. // emits a note about the value itself, apart from the literal.
err.note(&format!( err.note(fluent::lint::negative_note);
"the literal `{}` (decimal `{}`) does not fit into \ err.note(fluent::lint::negative_becomes_note);
the type `{}`",
repr_str, val, t
));
err.note(&format!("and the value `-{}` will become `{}{}`", repr_str, actually, t));
} else { } else {
err.note(&format!( err.note(fluent::lint::positive_note);
"the literal `{}` (decimal `{}`) does not fit into \
the type `{}` and will become `{}{}`",
repr_str, val, t, actually, t
));
} }
if let Some(sugg_ty) = if let Some(sugg_ty) =
get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative) 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') { if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos); let (sans_suffix, _) = repr_str.split_at(pos);
err.span_suggestion( err.span_suggestion(
expr.span, expr.span,
&format!("consider using the type `{}` instead", sugg_ty), fluent::lint::suggestion,
format!("{}{}", sans_suffix, sugg_ty), format!("{}{}", sans_suffix, sugg_ty),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} else { } 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(); err.emit();
}); });
} }
@ -353,21 +351,23 @@ fn lint_int_literal<'tcx>(
} }
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
let mut err = lint.build(&format!("literal out of range for `{}`", t.name_str())); let mut err = lint.build(fluent::lint::overflowing_int);
err.note(&format!( err.set_arg("ty", t.name_str());
"the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", err.set_arg(
"lit",
cx.sess() cx.sess()
.source_map() .source_map()
.span_to_snippet(lit.span) .span_to_snippet(lit.span)
.expect("must get snippet from literal"), .expect("must get snippet from literal"),
t.name_str(), );
min, err.set_arg("min", min);
max, err.set_arg("max", max);
)); err.note(fluent::lint::note);
if let Some(sugg_ty) = if let Some(sugg_ty) =
get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) 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(); err.emit();
}); });
@ -395,10 +395,10 @@ fn lint_uint_literal<'tcx>(
hir::ExprKind::Cast(..) => { hir::ExprKind::Cast(..) => {
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| { 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( .span_suggestion(
par_e.span, par_e.span,
"use a `char` literal instead", fluent::lint::suggestion,
format!("'\\u{{{:X}}}'", lit_val), format!("'\\u{{{:X}}}'", lit_val),
Applicability::MachineApplicable, Applicability::MachineApplicable,
) )
@ -429,17 +429,18 @@ fn lint_uint_literal<'tcx>(
return; return;
} }
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
lint.build(&format!("literal out of range for `{}`", t.name_str())) lint.build(fluent::lint::overflowing_uint)
.note(&format!( .set_arg("ty", t.name_str())
"the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", .set_arg(
"lit",
cx.sess() cx.sess()
.source_map() .source_map()
.span_to_snippet(lit.span) .span_to_snippet(lit.span)
.expect("must get snippet from literal"), .expect("must get snippet from literal"),
t.name_str(), )
min, .set_arg("min", min)
max, .set_arg("max", max)
)) .note(fluent::lint::note)
.emit(); .emit();
}); });
} }
@ -471,16 +472,16 @@ fn lint_literal<'tcx>(
}; };
if is_infinite == Ok(true) { if is_infinite == Ok(true) {
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
lint.build(&format!("literal out of range for `{}`", t.name_str())) lint.build(fluent::lint::overflowing_literal)
.note(&format!( .set_arg("ty", t.name_str())
"the literal `{}` does not fit into the type `{}` and will be converted to `{}::INFINITY`", .set_arg(
"lit",
cx.sess() cx.sess()
.source_map() .source_map()
.span_to_snippet(lit.span) .span_to_snippet(lit.span)
.expect("must get snippet from literal"), .expect("must get snippet from literal"),
t.name_str(), )
t.name_str(), .note(fluent::lint::note)
))
.emit(); .emit();
}); });
} }
@ -501,7 +502,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
hir::ExprKind::Binary(binop, ref l, ref r) => { hir::ExprKind::Binary(binop, ref l, ref r) => {
if is_comparison(binop) && !check_limits(cx, binop, &l, &r) { if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| { 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();
}); });
} }
} }
@ -663,7 +664,7 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
enum FfiResult<'tcx> { enum FfiResult<'tcx> {
FfiSafe, FfiSafe,
FfiPhantom(Ty<'tcx>), FfiPhantom(Ty<'tcx>),
FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> }, FfiUnsafe { ty: Ty<'tcx>, reason: DiagnosticMessage, help: Option<DiagnosticMessage> },
} }
pub(crate) fn nonnull_optimization_guaranteed<'tcx>( pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
@ -823,8 +824,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
self.emit_ffi_unsafe_type_lint( self.emit_ffi_unsafe_type_lint(
ty, ty,
sp, sp,
"passing raw arrays by value is not FFI-safe", fluent::lint::improper_ctypes_array_reason,
Some("consider passing a pointer to the array"), Some(fluent::lint::improper_ctypes_array_help),
); );
true true
} else { } else {
@ -867,11 +868,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} else { } else {
// All fields are ZSTs; this means that the type should behave // All fields are ZSTs; this means that the type should behave
// like (), which is FFI-unsafe // like (), which is FFI-unsafe
FfiUnsafe { FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None }
ty,
reason: "this struct contains only zero-sized fields".into(),
help: None,
}
} }
} else { } else {
// We can't completely trust repr(C) markings; make sure the fields are // We can't completely trust repr(C) markings; make sure the fields are
@ -885,7 +882,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiPhantom(..) if def.is_enum() => { FfiPhantom(..) if def.is_enum() => {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: "this enum contains a PhantomData field".into(), reason: fluent::lint::improper_ctypes_enum_phantomdata,
help: None, help: None,
}; };
} }
@ -921,7 +918,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} else { } else {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: "box cannot be represented as a single pointer".to_string(), reason: fluent::lint::improper_ctypes_box,
help: None, help: None,
}; };
} }
@ -931,17 +928,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} }
match def.adt_kind() { match def.adt_kind() {
AdtKind::Struct | AdtKind::Union => { AdtKind::Struct | AdtKind::Union => {
let kind = if def.is_struct() { "struct" } else { "union" };
if !def.repr().c() && !def.repr().transparent() { if !def.repr().c() && !def.repr().transparent() {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: format!("this {} has unspecified layout", kind), reason: if def.is_struct() {
help: Some(format!( fluent::lint::improper_ctypes_struct_layout_reason
"consider adding a `#[repr(C)]` or \ } else {
`#[repr(transparent)]` attribute to this {}", fluent::lint::improper_ctypes_union_layout_reason
kind },
)), help: if def.is_struct() {
Some(fluent::lint::improper_ctypes_struct_layout_help)
} else {
Some(fluent::lint::improper_ctypes_union_layout_help)
},
}; };
} }
@ -950,7 +949,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if is_non_exhaustive && !def.did().is_local() { if is_non_exhaustive && !def.did().is_local() {
return FfiUnsafe { return FfiUnsafe {
ty, 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, help: None,
}; };
} }
@ -958,8 +961,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if def.non_enum_variant().fields.is_empty() { if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: format!("this {} has no fields", kind), reason: if def.is_struct() {
help: Some(format!("consider adding a member to this {}", kind)), 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)
},
}; };
} }
@ -979,13 +990,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if repr_nullable_ptr(self.cx, ty, self.mode).is_none() { if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: "enum has no representation hint".into(), reason: fluent::lint::improper_ctypes_enum_repr_reason,
help: Some( help: Some(fluent::lint::improper_ctypes_enum_repr_help),
"consider adding a `#[repr(C)]`, \
`#[repr(transparent)]`, or integer `#[repr(...)]` \
attribute to this enum"
.into(),
),
}; };
} }
} }
@ -993,7 +999,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if def.is_variant_list_non_exhaustive() && !def.did().is_local() { if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: "this enum is non-exhaustive".into(), reason: fluent::lint::improper_ctypes_non_exhaustive,
help: None, help: None,
}; };
} }
@ -1004,7 +1010,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if is_non_exhaustive && !variant.def_id.is_local() { if is_non_exhaustive && !variant.def_id.is_local() {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: "this enum has non-exhaustive variants".into(), reason: fluent::lint::improper_ctypes_non_exhaustive_variant,
help: None, help: None,
}; };
} }
@ -1022,39 +1028,37 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
ty::Char => FfiUnsafe { ty::Char => FfiUnsafe {
ty, ty,
reason: "the `char` type has no C equivalent".into(), reason: fluent::lint::improper_ctypes_char_reason,
help: Some("consider using `u32` or `libc::wchar_t` instead".into()), help: Some(fluent::lint::improper_ctypes_char_help),
}, },
ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => FfiUnsafe { ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
ty, FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None }
reason: "128-bit integers don't currently have a known stable ABI".into(), }
help: None,
},
// Primitive types with a stable representation. // Primitive types with a stable representation.
ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
ty::Slice(_) => FfiUnsafe { ty::Slice(_) => FfiUnsafe {
ty, ty,
reason: "slices have no C equivalent".into(), reason: fluent::lint::improper_ctypes_slice_reason,
help: Some("consider using a raw pointer instead".into()), help: Some(fluent::lint::improper_ctypes_slice_help),
}, },
ty::Dynamic(..) => { 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::Str => FfiUnsafe {
ty, ty,
reason: "string slices have no C equivalent".into(), reason: fluent::lint::improper_ctypes_str_reason,
help: Some("consider using `*const u8` and a length instead".into()), help: Some(fluent::lint::improper_ctypes_str_help),
}, },
ty::Tuple(..) => FfiUnsafe { ty::Tuple(..) => FfiUnsafe {
ty, ty,
reason: "tuples have unspecified layout".into(), reason: fluent::lint::improper_ctypes_tuple_reason,
help: Some("consider using a struct instead".into()), help: Some(fluent::lint::improper_ctypes_tuple_help),
}, },
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
@ -1085,12 +1089,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if self.is_internal_abi(sig.abi()) { if self.is_internal_abi(sig.abi()) {
return FfiUnsafe { return FfiUnsafe {
ty, ty,
reason: "this function pointer has Rust-specific calling convention".into(), reason: fluent::lint::improper_ctypes_fnptr_reason,
help: Some( help: Some(fluent::lint::improper_ctypes_fnptr_help),
"consider using an `extern fn(...) -> ...` \
function pointer instead"
.into(),
),
}; };
} }
@ -1121,7 +1121,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// While opaque types are checked for earlier, if a projection in a struct field // 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. // normalizes to an opaque type, then it will reach this branch.
ty::Opaque(..) => { 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, // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
@ -1147,8 +1147,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
&mut self, &mut self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
sp: Span, sp: Span,
note: &str, note: DiagnosticMessage,
help: Option<&str>, help: Option<DiagnosticMessage>,
) { ) {
let lint = match self.mode { let lint = match self.mode {
CItemKind::Declaration => IMPROPER_CTYPES, CItemKind::Declaration => IMPROPER_CTYPES,
@ -1160,18 +1160,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
CItemKind::Declaration => "block", CItemKind::Declaration => "block",
CItemKind::Definition => "fn", CItemKind::Definition => "fn",
}; };
let mut diag = lint.build(&format!( let mut diag = lint.build(fluent::lint::improper_ctypes);
"`extern` {} uses type `{}`, which is not FFI-safe", diag.set_arg("ty", ty);
item_description, ty diag.set_arg("desc", item_description);
)); diag.span_label(sp, fluent::lint::label);
diag.span_label(sp, "not FFI-safe");
if let Some(help) = help { if let Some(help) = help {
diag.help(help); diag.help(help);
} }
diag.note(note); diag.note(note);
if let ty::Adt(def, _) = ty.kind() { if let ty::Adt(def, _) = ty.kind() {
if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { 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(); diag.emit();
@ -1208,7 +1207,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} }
if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { 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 true
} else { } else {
false false
@ -1250,13 +1249,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
FfiResult::FfiSafe => {} FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => { 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 // 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. // argument, which after substitution, is `()`, then this branch can be hit.
FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {} FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
FfiResult::FfiUnsafe { ty, reason, help } => { 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);
} }
} }
} }
@ -1383,12 +1387,9 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
VARIANT_SIZE_DIFFERENCES, VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span, enum_definition.variants[largest_index].span,
|lint| { |lint| {
lint.build(&format!( lint.build(fluent::lint::variant_size_differences)
"enum variant is more than three times \ .set_arg("largest", largest)
larger ({} bytes) than the next largest", .emit();
largest
))
.emit();
}, },
); );
} }
@ -1511,13 +1512,13 @@ impl InvalidAtomicOrdering {
{ {
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
if method == sym::load { if method == sym::load {
diag.build("atomic loads cannot have `Release` or `AcqRel` ordering") diag.build(fluent::lint::atomic_ordering_load)
.help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`") .help(fluent::lint::help)
.emit() .emit()
} else { } else {
debug_assert_eq!(method, sym::store); debug_assert_eq!(method, sym::store);
diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering") diag.build(fluent::lint::atomic_ordering_store)
.help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`") .help(fluent::lint::help)
.emit(); .emit();
} }
}); });
@ -1532,8 +1533,8 @@ impl InvalidAtomicOrdering {
&& Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed) && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
{ {
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
diag.build("memory fences cannot have `Relaxed` ordering") diag.build(fluent::lint::atomic_ordering_fence)
.help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`") .help(fluent::lint::help)
.emit(); .emit();
}); });
} }
@ -1553,13 +1554,11 @@ impl InvalidAtomicOrdering {
if matches!(fail_ordering, sym::Release | sym::AcqRel) { if matches!(fail_ordering, sym::Release | sym::AcqRel) {
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg.span, |diag| { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg.span, |diag| {
diag.build(&format!( diag.build(fluent::lint::atomic_ordering_invalid)
"`{method}`'s failure ordering may not be `Release` or `AcqRel`, \ .set_arg("method", method)
since a failed `{method}` does not result in a write", .span_label(fail_order_arg.span, fluent::lint::label)
)) .help(fluent::lint::help)
.span_label(fail_order_arg.span, "invalid failure ordering") .emit();
.help("consider using `Acquire` or `Relaxed` failure ordering instead")
.emit();
}); });
} }
@ -1577,18 +1576,20 @@ impl InvalidAtomicOrdering {
fail_ordering fail_ordering
}; };
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, success_order_arg.span, |diag| { cx.struct_span_lint(INVALID_ATOMIC_ORDERING, success_order_arg.span, |diag| {
diag.build(&format!( diag.build(fluent::lint::atomic_ordering_invalid_fail_success)
"`{method}`'s success ordering must be at least as strong as its failure ordering" .set_arg("method", method)
)) .set_arg("fail_ordering", fail_ordering)
.span_label(fail_order_arg.span, format!("`{fail_ordering}` failure ordering")) .set_arg("success_ordering", success_ordering)
.span_label(success_order_arg.span, format!("`{success_ordering}` success ordering")) .set_arg("success_suggestion", success_suggestion)
.span_suggestion_short( .span_label(fail_order_arg.span, fluent::lint::fail_label)
success_order_arg.span, .span_label(success_order_arg.span, fluent::lint::success_label)
format!("consider using `{success_suggestion}` success ordering instead"), .span_suggestion_short(
format!("std::sync::atomic::Ordering::{success_suggestion}"), success_order_arg.span,
Applicability::MaybeIncorrect, fluent::lint::suggestion,
) format!("std::sync::atomic::Ordering::{success_suggestion}"),
.emit(); Applicability::MaybeIncorrect,
)
.emit();
}); });
} }
} }

View file

@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::util::{classify, parser}; use rustc_ast::util::{classify, parser};
use rustc_ast::{ExprKind, StmtKind}; 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 as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId; 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 { if let Some(must_use_op) = must_use_op {
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| { 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.build(fluent::lint::unused_op)
lint.span_label(expr.span, &format!("the {} produces a value", must_use_op)); .set_arg("op", must_use_op)
lint.span_suggestion_verbose( .span_label(expr.span, fluent::lint::label)
expr.span.shrink_to_lo(), .span_suggestion_verbose(
"use `let _ = ...` to ignore the resulting value", expr.span.shrink_to_lo(),
"let _ = ", fluent::lint::suggestion,
Applicability::MachineApplicable, "let _ = ",
); Applicability::MachineApplicable,
lint.emit(); )
.emit();
}); });
op_warned = true; op_warned = true;
} }
if !(type_permits_lack_of_use || fn_warned || op_warned) { if !(type_permits_lack_of_use || fn_warned || op_warned) {
cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| { 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(..) => { ty::Closure(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let mut err = lint.build(&format!( // FIXME(davidtwco): this isn't properly translatable becauses of the
"unused {}closure{}{} that must be used", // pre/post strings
descr_pre, plural_suffix, descr_post, lint.build(fluent::lint::unused_closure)
)); .set_arg("count", plural_len)
err.note("closures are lazy and do nothing unless called"); .set_arg("pre", descr_pre)
err.emit(); .set_arg("post", descr_post)
.note(fluent::lint::note)
.emit();
}); });
true true
} }
ty::Generator(..) => { ty::Generator(..) => {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let mut err = lint.build(&format!( // FIXME(davidtwco): this isn't properly translatable becauses of the
"unused {}generator{}{} that must be used", // pre/post strings
descr_pre, plural_suffix, descr_post, lint.build(fluent::lint::unused_generator)
)); .set_arg("count", plural_len)
err.note("generators are lazy and do nothing unless resumed"); .set_arg("pre", descr_pre)
err.emit(); .set_arg("post", descr_post)
.note(fluent::lint::note)
.emit();
}); });
true true
} }
@ -305,13 +310,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
) -> bool { ) -> bool {
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!( // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post
"unused {}`{}`{} that must be used", // strings
descr_pre_path, let mut err = lint.build(fluent::lint::unused_def);
cx.tcx.def_path_str(def_id), err.set_arg("pre", descr_pre_path);
descr_post_path err.set_arg("post", descr_post_path);
); err.set_arg("def", cx.tcx.def_path_str(def_id));
let mut err = lint.build(&msg);
// check for #[must_use = "..."] // check for #[must_use = "..."]
if let Some(note) = attr.value_str() { if let Some(note) = attr.value_str() {
err.note(note.as_str()); err.note(note.as_str());
@ -356,20 +360,20 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| { cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
let ty = cx.typeck_results().expr_ty(expr); let ty = cx.typeck_results().expr_ty(expr);
if ty.needs_drop(cx.tcx, cx.param_env) { 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) { if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
lint.span_suggestion( lint.span_suggestion(
s.span, s.span,
"use `drop` to clarify the intent", fluent::lint::suggestion,
format!("drop({});", snippet), format!("drop({});", snippet),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} else { } else {
lint.span_help(s.span, "use `drop` to clarify the intent"); lint.span_help(s.span, fluent::lint::suggestion);
} }
lint.emit(); lint.emit();
} else { } else {
lint.build("path statement with no effect").emit(); lint.build(fluent::lint::path_statement_no_effect).emit();
} }
}); });
} }
@ -540,15 +544,19 @@ trait UnusedDelimLint {
} }
cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| { 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![ let replacement = vec![
(spans.0, if keep_space.0 { " ".into() } else { "".into() }), (spans.0, if keep_space.0 { " ".into() } else { "".into() }),
(spans.1, if keep_space.1 { " ".into() } else { "".into() }), (spans.1, if keep_space.1 { " ".into() } else { "".into() }),
]; ];
let suggestion = format!("remove these {}", Self::DELIM_STR); lint.build(fluent::lint::unused_delim)
err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable); .set_arg("delim", Self::DELIM_STR)
err.emit(); .set_arg("item", msg)
.multipart_suggestion(
fluent::lint::suggestion,
replacement,
Applicability::MachineApplicable,
)
.emit();
}); });
} }
@ -1110,7 +1118,7 @@ impl UnusedImportBraces {
}; };
cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| { 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();
}); });
} }
} }
@ -1161,15 +1169,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
for adj in cx.typeck_results().expr_adjustments(e) { for adj in cx.typeck_results().expr_adjustments(e) {
if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind { if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| { cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
let msg = match m { lint.build(match m {
adjustment::AutoBorrowMutability::Not => { adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
"unnecessary allocation, use `&` instead"
}
adjustment::AutoBorrowMutability::Mut { .. } => { adjustment::AutoBorrowMutability::Mut { .. } => {
"unnecessary allocation, use `&mut` instead" fluent::lint::unused_allocation_mut
} }
}; })
lint.build(msg).emit(); .emit();
}); });
} }
} }

View file

@ -3,7 +3,8 @@ use std::cmp;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{ use rustc_errors::{
Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed, MultiSpan, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee,
ErrorGuaranteed, MultiSpan,
}; };
use rustc_hir::HirId; use rustc_hir::HirId;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
@ -231,7 +232,7 @@ pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a,
impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> { impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
/// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`. /// 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<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> {
self.0.set_primary_message(msg); self.0.set_primary_message(msg);
self.0.set_is_lint(); self.0.set_is_lint();
self.0 self.0

View file

@ -611,6 +611,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> 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(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)] #[derive(HashStable, TypeFoldable)]
pub enum PredicateKind<'tcx> { pub enum PredicateKind<'tcx> {

View file

@ -550,7 +550,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
id, id,
span, span,
|lint| { |lint| {
lint.build(&msg).emit(); lint.build(msg).emit();
}, },
); );
} }

View file

@ -1163,7 +1163,7 @@ impl CheckAttrVisitor<'_> {
hir_id, hir_id,
meta.span(), meta.span(),
|lint| { |lint| {
lint.build(&"invalid `doc` attribute").emit(); lint.build("invalid `doc` attribute").emit();
}, },
); );
is_valid = false; is_valid = false;

View file

@ -2356,6 +2356,9 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
/// with the argument order swapped. /// 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 /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
/// ///
/// # Safety /// # Safety
@ -2461,6 +2464,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
/// order swapped. Copying takes place as if the bytes were copied from `src` /// 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`. /// 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 /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
/// ///
/// # Safety /// # Safety

View file

@ -730,7 +730,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
/// Swaps the values at two mutable locations of the same type, without /// Swaps the values at two mutable locations of the same type, without
/// deinitializing either. /// 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`]: /// equivalent to [`mem::swap`]:
/// ///
/// * It operates on raw pointers instead of references. When references are /// * It operates on raw pointers instead of references. When references are
@ -740,6 +740,9 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
/// overlapping region of memory from `x` will be used. This is demonstrated /// overlapping region of memory from `x` will be used. This is demonstrated
/// in the second example below. /// 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 /// # Safety
/// ///
/// Behavior is undefined if any of the following conditions are violated: /// Behavior is undefined if any of the following conditions are violated:
@ -816,6 +819,9 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
/// Swaps `count * size_of::<T>()` bytes between the two regions of memory /// Swaps `count * size_of::<T>()` bytes between the two regions of memory
/// beginning at `x` and `y`. The two regions must *not* overlap. /// 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 /// # Safety
/// ///
/// Behavior is undefined if any of the following conditions are violated: /// Behavior is undefined if any of the following conditions are violated:
@ -861,15 +867,15 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
if mem::align_of::<T>() >= mem::align_of::<$ChunkTy>() if mem::align_of::<T>() >= mem::align_of::<$ChunkTy>()
&& mem::size_of::<T>() % mem::size_of::<$ChunkTy>() == 0 && mem::size_of::<T>() % mem::size_of::<$ChunkTy>() == 0
{ {
let x: *mut MaybeUninit<$ChunkTy> = x.cast(); let x: *mut $ChunkTy = x.cast();
let y: *mut MaybeUninit<$ChunkTy> = y.cast(); let y: *mut $ChunkTy = y.cast();
let count = count * (mem::size_of::<T>() / mem::size_of::<$ChunkTy>()); let count = count * (mem::size_of::<T>() / mem::size_of::<$ChunkTy>());
// SAFETY: these are the same bytes that the caller promised were // SAFETY: these are the same bytes that the caller promised were
// ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s. // ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s.
// The `if` condition above ensures that we're not violating // The `if` condition above ensures that we're not violating
// alignment requirements, and that the division is exact so // alignment requirements, and that the division is exact so
// that we don't lose any bytes off the end. // 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) };
} }
}; };
} }
@ -902,7 +908,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
} }
// SAFETY: Same preconditions as this function // 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`] /// Same behaviour and safety conditions as [`swap_nonoverlapping`]
@ -911,17 +917,17 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
/// `swap_nonoverlapping` tries to use) so no need to manually SIMD it. /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it.
#[inline] #[inline]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
const unsafe fn swap_nonoverlapping_simple<T>(x: *mut T, y: *mut T, count: usize) { const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, count: usize) {
let x = x.cast::<MaybeUninit<T>>();
let y = y.cast::<MaybeUninit<T>>();
let mut i = 0; let mut i = 0;
while i < count { while i < count {
let x: &mut T = // SAFETY: By precondition, `i` is in-bounds because it's below `n`
// SAFETY: By precondition, `i` is in-bounds because it's below `n` let x = unsafe { &mut *x.add(i) };
unsafe { &mut *x.add(i) }; // SAFETY: By precondition, `i` is in-bounds because it's below `n`
let y: &mut T = // and it's distinct from `x` since the ranges are non-overlapping
// SAFETY: By precondition, `i` is in-bounds because it's below `n` let y = unsafe { &mut *y.add(i) };
// and it's distinct from `x` since the ranges are non-overlapping mem::swap_simple::<MaybeUninit<T>>(x, y);
unsafe { &mut *y.add(i) };
mem::swap_simple(x, y);
i += 1; i += 1;
} }

View file

@ -781,6 +781,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] #[test]
fn test_const_copy() { fn test_const_copy() {
const { const {

View file

@ -1739,6 +1739,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
/* Media Queries */ /* 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) { @media (min-width: 701px) {
/* In case there is no documentation before a code block, we need to add some margin at the top /* 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. to prevent an overlay between the "collapse toggle" and the information tooltip.
@ -1759,6 +1764,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) { @media (max-width: 700px) {
/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar, /* 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 or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured

View file

@ -12,6 +12,12 @@
const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value; const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
let oldScrollPosition = 0; let oldScrollPosition = 0;
function closeSidebarIfMobile() {
if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
updateLocalStorage("source-sidebar-show", "false");
}
}
function createDirEntry(elem, parent, fullPath, hasFoundFile) { function createDirEntry(elem, parent, fullPath, hasFoundFile) {
const dirEntry = document.createElement("details"); const dirEntry = document.createElement("details");
const summary = document.createElement("summary"); const summary = document.createElement("summary");
@ -42,6 +48,7 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
const file = document.createElement("a"); const file = document.createElement("a");
file.innerText = file_text; file.innerText = file_text;
file.href = rootPath + "src/" + fullPath + file_text + ".html"; file.href = rootPath + "src/" + fullPath + file_text + ".html";
file.addEventListener("click", closeSidebarIfMobile);
const w = window.location.href.split("#")[0]; const w = window.location.href.split("#")[0];
if (!hasFoundFile && w === file.href) { if (!hasFoundFile && w === file.href) {
file.className = "selected"; file.className = "selected";
@ -59,7 +66,7 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
function toggleSidebar() { function toggleSidebar() {
const child = this.parentNode.children[0]; const child = this.parentNode.children[0];
if (child.innerText === ">") { if (child.innerText === ">") {
if (window.innerWidth < 701) { if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
// This is to keep the scroll position on mobile. // This is to keep the scroll position on mobile.
oldScrollPosition = window.scrollY; oldScrollPosition = window.scrollY;
document.body.style.position = "fixed"; document.body.style.position = "fixed";
@ -69,7 +76,7 @@ function toggleSidebar() {
child.innerText = "<"; child.innerText = "<";
updateLocalStorage("source-sidebar-show", "true"); updateLocalStorage("source-sidebar-show", "true");
} else { } else {
if (window.innerWidth < 701) { if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
// This is to keep the scroll position on mobile. // This is to keep the scroll position on mobile.
document.body.style.position = ""; document.body.style.position = "";
document.body.style.top = ""; document.body.style.top = "";

View file

@ -9,6 +9,11 @@ const darkThemes = ["dark", "ayu"];
window.currentTheme = document.getElementById("themeStyle"); window.currentTheme = document.getElementById("themeStyle");
window.mainTheme = document.getElementById("mainThemeStyle"); 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 settingsDataset = (function() {
const settingsElement = document.getElementById("default-settings"); const settingsElement = document.getElementById("default-settings");
if (settingsElement === null) { if (settingsElement === null) {

View file

@ -18,6 +18,17 @@ click: "#sidebar-toggle"
// Because of the transition CSS, we check by using `wait-for-css` instead of `assert-css`. // 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}) 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
wait-for-css: (".sidebar", {"width": "300px"})
assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
// Now we check the display of the sidebar items. // Now we check the display of the sidebar items.
show-text: true show-text: true
@ -221,3 +232,23 @@ click: "#sidebar-toggle"
wait-for-css: (".sidebar", {"width": "0px"}) wait-for-css: (".sidebar", {"width": "0px"})
// The "scrollTop" property should be the same. // The "scrollTop" property should be the same.
assert-window-property: {"pageYOffset": "2519"} 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: ("#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"}

View file

@ -5,21 +5,11 @@
extern crate inner; extern crate inner;
/// [mod@std::env] [g] /// [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 outer/index.html
// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env" // @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
// @ has - '//a[@href="fn.f.html"]' "g" // @has - '//a[@href="fn.f.html"]' "g"
pub use f as 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 // Make sure the documentation is actually correct by documenting an inlined re-export
/// [mod@std::env] /// [mod@std::env]
// @has outer/fn.f.html // @has outer/fn.f.html

View file

@ -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 --> $DIR/existing_doc_keyword.rs:10:1
| |
LL | #[doc(keyword = "tadam")] LL | #[doc(keyword = "tadam")]

View file

@ -1,6 +1,8 @@
// check-fail // check-fail
// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] // 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, // 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 // changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
// the test is just ignored on stable and beta: // the test is just ignored on stable and beta:

View file

@ -1,5 +1,5 @@
error: `#[derive(SessionDiagnostic)]` can only be used on structs 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 | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
LL | | LL | |
@ -10,13 +10,13 @@ LL | | }
| |_^ | |_^
error: `#[error = ...]` is not a valid attribute error: `#[error = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:46:1 --> $DIR/diagnostic-derive.rs:48:1
| |
LL | #[error = "E0123"] LL | #[error = "E0123"]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: `#[nonsense(...)]` is not a valid attribute 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")] 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 = help: only `error`, `warning`, `help` and `note` are valid attributes
error: diagnostic kind not specified 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 | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
LL | | LL | |
@ -36,7 +36,7 @@ LL | | struct InvalidStructAttr {}
= help: use the `#[error(...)]` attribute to create an error = help: use the `#[error(...)]` attribute to create an error
error: `#[error("...")]` is not a valid attribute error: `#[error("...")]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:58:9 --> $DIR/diagnostic-derive.rs:60:9
| |
LL | #[error("E0123")] LL | #[error("E0123")]
| ^^^^^^^ | ^^^^^^^
@ -44,7 +44,7 @@ LL | #[error("E0123")]
= help: first argument of the attribute should be the diagnostic slug = help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified error: diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:58:1 --> $DIR/diagnostic-derive.rs:60:1
| |
LL | / #[error("E0123")] LL | / #[error("E0123")]
LL | | 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)]` = 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 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")] 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 = help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified 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 | / #[error(nonsense("foo"), code = "E0123", slug = "foo")]
LL | | 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)]` = 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 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")] 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 = help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified 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 | / #[error(nonsense = "...", code = "E0123", slug = "foo")]
LL | | 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)]` = 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 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")] 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 = help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified 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 | / #[error(nonsense = 4, code = "E0123", slug = "foo")]
LL | | 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)]` = 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 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")] 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 = help: only `code` is a valid nested attributes following the slug
error: `#[suggestion = ...]` is not a valid attribute error: `#[suggestion = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:94:5 --> $DIR/diagnostic-derive.rs:96:5
| |
LL | #[suggestion = "bar"] LL | #[suggestion = "bar"]
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times error: specified multiple times
--> $DIR/diagnostic-derive.rs:101:1 --> $DIR/diagnostic-derive.rs:103:1
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: previously specified here note: previously specified here
--> $DIR/diagnostic-derive.rs:100:1 --> $DIR/diagnostic-derive.rs:102:1
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times error: specified multiple times
--> $DIR/diagnostic-derive.rs:101:1 --> $DIR/diagnostic-derive.rs:103:1
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: previously specified here note: previously specified here
--> $DIR/diagnostic-derive.rs:100:1 --> $DIR/diagnostic-derive.rs:102:1
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times error: specified multiple times
--> $DIR/diagnostic-derive.rs:101:50 --> $DIR/diagnostic-derive.rs:103:50
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^ | ^^^^^^^
| |
note: previously specified here note: previously specified here
--> $DIR/diagnostic-derive.rs:100:50 --> $DIR/diagnostic-derive.rs:102:50
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^ | ^^^^^^^
error: specified multiple times error: specified multiple times
--> $DIR/diagnostic-derive.rs:109:1 --> $DIR/diagnostic-derive.rs:111:1
| |
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: previously specified here note: previously specified here
--> $DIR/diagnostic-derive.rs:108:1 --> $DIR/diagnostic-derive.rs:110:1
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times error: specified multiple times
--> $DIR/diagnostic-derive.rs:109:1 --> $DIR/diagnostic-derive.rs:111:1
| |
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: previously specified here note: previously specified here
--> $DIR/diagnostic-derive.rs:108:1 --> $DIR/diagnostic-derive.rs:110:1
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times error: specified multiple times
--> $DIR/diagnostic-derive.rs:109:52 --> $DIR/diagnostic-derive.rs:111:52
| |
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")] LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
| ^^^^^^^ | ^^^^^^^
| |
note: previously specified here note: previously specified here
--> $DIR/diagnostic-derive.rs:108:50 --> $DIR/diagnostic-derive.rs:110:50
| |
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^ | ^^^^^^^
error: specified multiple times 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")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
| ^^^^^^^ | ^^^^^^^
| |
note: previously specified here 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")] LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
| ^^^^^^^ | ^^^^^^^
error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute 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")] LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostic kind not specified error: diagnostic kind not specified
--> $DIR/diagnostic-derive.rs:126:1 --> $DIR/diagnostic-derive.rs:128:1
| |
LL | struct KindNotProvided {} LL | struct KindNotProvided {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -224,7 +224,7 @@ LL | struct KindNotProvided {}
= help: use the `#[error(...)]` attribute to create an error = help: use the `#[error(...)]` attribute to create an error
error: diagnostic slug not specified error: diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:129:1 --> $DIR/diagnostic-derive.rs:131:1
| |
LL | / #[error(code = "E0456")] LL | / #[error(code = "E0456")]
LL | | 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)]` = 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` 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] LL | #[primary_span]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: `#[nonsense]` is not a valid attribute error: `#[nonsense]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:148:5 --> $DIR/diagnostic-derive.rs:150:5
| |
LL | #[nonsense] LL | #[nonsense]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -248,19 +248,19 @@ LL | #[nonsense]
= help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes = 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` 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)] LL | #[label(typeck::label)]
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
error: `name` doesn't refer to a field on this type 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}")] LL | #[suggestion(typeck::suggestion, code = "{name}")]
| ^^^^^^^^ | ^^^^^^^^
error: invalid format string: expected `'}'` but string was terminated error: invalid format string: expected `'}'` but string was terminated
--> $DIR/diagnostic-derive.rs:178:16 --> $DIR/diagnostic-derive.rs:180:16
| |
LL | #[derive(SessionDiagnostic)] LL | #[derive(SessionDiagnostic)]
| - ^ expected `'}'` in format string | - ^ 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) = 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 error: invalid format string: unmatched `}` found
--> $DIR/diagnostic-derive.rs:188:15 --> $DIR/diagnostic-derive.rs:190:15
| |
LL | #[derive(SessionDiagnostic)] LL | #[derive(SessionDiagnostic)]
| ^ unmatched `}` in format string | ^ 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) = 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` 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)] LL | #[label(typeck::label)]
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
error: `#[suggestion(nonsense = ...)]` is not a valid attribute error: `#[suggestion(nonsense = ...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:233:18 --> $DIR/diagnostic-derive.rs:235:18
| |
LL | #[suggestion(nonsense = "bar")] LL | #[suggestion(nonsense = "bar")]
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -294,7 +294,7 @@ LL | #[suggestion(nonsense = "bar")]
= help: only `message`, `code` and `applicability` are valid field attributes = help: only `message`, `code` and `applicability` are valid field attributes
error: `#[suggestion(msg = ...)]` is not a valid attribute error: `#[suggestion(msg = ...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:241:18 --> $DIR/diagnostic-derive.rs:243:18
| |
LL | #[suggestion(msg = "bar")] LL | #[suggestion(msg = "bar")]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -302,7 +302,7 @@ LL | #[suggestion(msg = "bar")]
= help: only `message`, `code` and `applicability` are valid field attributes = help: only `message`, `code` and `applicability` are valid field attributes
error: wrong field type for suggestion 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 | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
LL | | LL | |
@ -312,7 +312,7 @@ LL | | suggestion: Applicability,
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, 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` 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 | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
LL | | LL | |
@ -320,7 +320,7 @@ LL | | suggestion: (Span, Span, Applicability),
| |___________________________________________^ | |___________________________________________^
error: type of field annotated with `#[suggestion(...)]` contains more than one 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 | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
LL | | LL | |
@ -328,72 +328,66 @@ LL | | suggestion: (Applicability, Applicability, Span),
| |____________________________________________________^ | |____________________________________________________^
error: `#[label = ...]` is not a valid attribute error: `#[label = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:294:5 --> $DIR/diagnostic-derive.rs:296:5
| |
LL | #[label = "bar"] LL | #[label = "bar"]
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
error: applicability cannot be set in both the field and attribute 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")] LL | #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: invalid applicability error: invalid applicability
--> $DIR/diagnostic-derive.rs:453:52 --> $DIR/diagnostic-derive.rs:455:52
| |
LL | #[suggestion(typeck::suggestion, code = "...", applicability = "batman")] LL | #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(...)]` is not a valid attribute error: `#[label(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:516:5 --> $DIR/diagnostic-derive.rs:518:5
| |
LL | #[label(typeck::label, foo)] LL | #[label(typeck::label, foo)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(...)]` is not a valid attribute error: `#[label(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:524:5 --> $DIR/diagnostic-derive.rs:526:5
| |
LL | #[label(typeck::label, foo = "...")] LL | #[label(typeck::label, foo = "...")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(...)]` is not a valid attribute error: `#[label(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:532:5 --> $DIR/diagnostic-derive.rs:534:5
| |
LL | #[label(typeck::label, foo("..."))] LL | #[label(typeck::label, foo("..."))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: cannot find attribute `nonsense` in this scope 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")] LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^ | ^^^^^^^^
error: cannot find attribute `nonsense` in this scope error: cannot find attribute `nonsense` in this scope
--> $DIR/diagnostic-derive.rs:148:7 --> $DIR/diagnostic-derive.rs:150:7
| |
LL | #[nonsense] LL | #[nonsense]
| ^^^^^^^^ | ^^^^^^^^
error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent` 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")] LL | #[error(nonsense, code = "E0123")]
| ^^^^^^^^ not found in `rustc_errors::fluent` | ^^^^^^^^ not found in `rustc_errors::fluent`
error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied 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)] LL | #[derive(SessionDiagnostic)]
| ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello` | ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
| |
= help: the following other types implement trait `IntoDiagnosticArg`: = help: normalized in stderr
&'a str
Ident
String
Symbol
rustc_middle::ty::Ty<'tcx>
usize
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:538:19 --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:538:19
| |

View file

@ -5,9 +5,9 @@ LL | panic!({ "foo" });
| ^^^^^^^^^ | ^^^^^^^^^
| |
= note: `#[warn(non_fmt_panics)]` on by default = 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!("{}", { "foo" }); LL | panic!("{}", { "foo" });
| +++++ | +++++

View file

@ -73,9 +73,9 @@ warning: panic message is not a string literal
LL | assert!(false, S); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | assert!(false, "{}", S); LL | assert!(false, "{}", S);
| +++++ | +++++
@ -86,9 +86,9 @@ warning: panic message is not a string literal
LL | assert!(false, 123); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | assert!(false, "{}", 123); LL | assert!(false, "{}", 123);
| +++++ | +++++
@ -99,9 +99,9 @@ warning: panic message is not a string literal
LL | assert!(false, Some(123)); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{:?}" format string to use the Debug implementation of `Option<i32>` help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>`
| |
LL | assert!(false, "{:?}", Some(123)); LL | assert!(false, "{:?}", Some(123));
| +++++++ | +++++++
@ -124,9 +124,9 @@ warning: panic message is not a string literal
LL | panic!(C); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!("{}", C); LL | panic!("{}", C);
| +++++ | +++++
@ -137,9 +137,9 @@ warning: panic message is not a string literal
LL | panic!(S); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!("{}", S); LL | panic!("{}", S);
| +++++ | +++++
@ -150,9 +150,9 @@ warning: panic message is not a string literal
LL | unreachable!(S); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | unreachable!("{}", S); LL | unreachable!("{}", S);
| +++++ | +++++
@ -163,9 +163,9 @@ warning: panic message is not a string literal
LL | unreachable!(S); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | unreachable!("{}", S); LL | unreachable!("{}", S);
| +++++ | +++++
@ -176,9 +176,9 @@ warning: panic message is not a string literal
LL | std::panic!(123); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | std::panic!("{}", 123); LL | std::panic!("{}", 123);
| +++++ | +++++
@ -193,9 +193,9 @@ warning: panic message is not a string literal
LL | core::panic!(&*"abc"); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | core::panic!("{}", &*"abc"); LL | core::panic!("{}", &*"abc");
| +++++ | +++++
@ -206,9 +206,9 @@ warning: panic message is not a string literal
LL | panic!(Some(123)); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{:?}" format string to use the Debug implementation of `Option<i32>` help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>`
| |
LL | panic!("{:?}", Some(123)); LL | panic!("{:?}", Some(123));
| +++++++ | +++++++
@ -259,9 +259,9 @@ warning: panic message is not a string literal
LL | panic!(a!()); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!("{}", a!()); LL | panic!("{}", a!());
| +++++ | +++++
@ -276,9 +276,9 @@ warning: panic message is not a string literal
LL | unreachable!(a!()); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | unreachable!("{}", a!()); LL | unreachable!("{}", a!());
| +++++ | +++++
@ -289,9 +289,9 @@ warning: panic message is not a string literal
LL | panic!(format!("{}", 1)); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
= 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 help: remove the `format!(..)` macro call
| |
LL - panic!(format!("{}", 1)); LL - panic!(format!("{}", 1));
@ -304,9 +304,9 @@ warning: panic message is not a string literal
LL | unreachable!(format!("{}", 1)); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
= 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 help: remove the `format!(..)` macro call
| |
LL - unreachable!(format!("{}", 1)); LL - unreachable!(format!("{}", 1));
@ -319,9 +319,9 @@ warning: panic message is not a string literal
LL | assert!(false, format!("{}", 1)); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
= 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 help: remove the `format!(..)` macro call
| |
LL - assert!(false, format!("{}", 1)); LL - assert!(false, format!("{}", 1));
@ -334,9 +334,9 @@ warning: panic message is not a string literal
LL | debug_assert!(false, format!("{}", 1)); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
= 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 help: remove the `format!(..)` macro call
| |
LL - debug_assert!(false, format!("{}", 1)); LL - debug_assert!(false, format!("{}", 1));
@ -349,9 +349,9 @@ warning: panic message is not a string literal
LL | panic![123]; 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!["{}", 123]; LL | panic!["{}", 123];
| +++++ | +++++
@ -366,9 +366,9 @@ warning: panic message is not a string literal
LL | panic!{123}; 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!{"{}", 123}; LL | panic!{"{}", 123};
| +++++ | +++++
@ -385,7 +385,7 @@ LL | panic!(v);
| | | |
| help: use std::panic::panic_any instead: `std::panic::panic_any` | 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
warning: panic message is not a string literal warning: panic message is not a string literal
@ -394,7 +394,7 @@ warning: panic message is not a string literal
LL | assert!(false, v); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
warning: panic message is not a string literal warning: panic message is not a string literal
@ -403,9 +403,9 @@ warning: panic message is not a string literal
LL | panic!(v); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
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); LL | panic!("{:?}", v);
| +++++++ | +++++++
@ -420,9 +420,9 @@ warning: panic message is not a string literal
LL | assert!(false, v); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
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); LL | assert!(false, "{:?}", v);
| +++++++ | +++++++
@ -433,9 +433,9 @@ warning: panic message is not a string literal
LL | panic!(v); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!("{}", v); LL | panic!("{}", v);
| +++++ | +++++
@ -450,9 +450,9 @@ warning: panic message is not a string literal
LL | assert!(false, v); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | assert!(false, "{}", v); LL | assert!(false, "{}", v);
| +++++ | +++++
@ -463,9 +463,9 @@ warning: panic message is not a string literal
LL | panic!(v); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | panic!("{}", v); LL | panic!("{}", v);
| +++++ | +++++
@ -480,9 +480,9 @@ warning: panic message is not a string literal
LL | assert!(false, v); 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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
help: add a "{}" format string to Display the message help: add a "{}" format string to `Display` the message
| |
LL | assert!(false, "{}", v); LL | assert!(false, "{}", v);
| +++++ | +++++

@ -1 +1 @@
Subproject commit b74e96f509baf0be70281c55f14cb18fefbc6b22 Subproject commit 75b22326dad1914c22484ab6672de5cae94f7457