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.
fluent_messages! {
borrowck => "../locales/en-US/borrowck.ftl",
builtin_macros => "../locales/en-US/builtin_macros.ftl",
lint => "../locales/en-US/lint.ftl",
parser => "../locales/en-US/parser.ftl",
privacy => "../locales/en-US/privacy.ftl",
typeck => "../locales/en-US/typeck.ftl",
builtin_macros => "../locales/en-US/builtin_macros.ftl",
borrowck => "../locales/en-US/borrowck.ftl",
}
pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};

View file

@ -8,7 +8,7 @@ use rustc_error_messages::FluentValue;
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::{edition::Edition, Span, DUMMY_SP};
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
@ -39,12 +39,94 @@ pub trait IntoDiagnosticArg {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
}
impl IntoDiagnosticArg for bool {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
if self {
DiagnosticArgValue::Str(Cow::Borrowed("true"))
} else {
DiagnosticArgValue::Str(Cow::Borrowed("false"))
}
}
}
impl IntoDiagnosticArg for 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 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
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 {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
self.to_ident_string().into_diagnostic_arg()

View file

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

View file

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

View file

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

View file

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

View file

@ -1,4 +1,5 @@
use crate::builtin;
use rustc_errors::fluent;
use rustc_hir::HirId;
use rustc_middle::ty::query::Providers;
use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
@ -43,13 +44,13 @@ fn emit_unfulfilled_expectation_lint(
hir_id,
expectation.emission_span,
|diag| {
let mut diag = diag.build("this lint expectation is unfulfilled");
let mut diag = diag.build(fluent::lint::expectation);
if let Some(rationale) = expectation.reason {
diag.note(rationale.as_str());
}
if expectation.is_unfulfilled_lint_expectations {
diag.note("the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message");
diag.note(fluent::lint::note);
}
diag.emit();

View file

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

View file

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

View file

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

View file

@ -1,6 +1,7 @@
use crate::LateContext;
use crate::LateLintPass;
use crate::LintContext;
use rustc_errors::fluent;
use rustc_hir::{Expr, ExprKind, PathSegment};
use rustc_middle::ty;
use rustc_span::{symbol::sym, ExpnKind, Span};
@ -88,16 +89,12 @@ fn lint_cstring_as_ptr(
if let ty::Adt(adt, _) = substs.type_at(0).kind() {
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
let mut diag = diag
.build("getting the inner pointer of a temporary `CString`");
diag.span_label(as_ptr_span, "this pointer will be invalid");
diag.span_label(
unwrap.span,
"this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime",
);
diag.note("pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned");
diag.help("for more information, see https://doc.rust-lang.org/reference/destructors.html");
diag.emit();
diag.build(fluent::lint::cstring_ptr)
.span_label(as_ptr_span, fluent::lint::as_ptr_label)
.span_label(unwrap.span, fluent::lint::unwrap_label)
.note(fluent::lint::note)
.help(fluent::lint::help)
.emit();
});
}
}

View file

@ -1,6 +1,7 @@
use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::fluent;
use rustc_span::symbol::Symbol;
declare_lint! {
@ -180,13 +181,13 @@ impl EarlyLintPass for NonAsciiIdents {
}
has_non_ascii_idents = true;
cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
lint.build("identifier contains non-ASCII characters").emit();
lint.build(fluent::lint::identifier_non_ascii_char).emit();
});
if check_uncommon_codepoints
&& !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
{
cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
lint.build("identifier contains uncommon Unicode codepoints").emit();
lint.build(fluent::lint::identifier_uncommon_codepoints).emit();
})
}
}
@ -216,15 +217,11 @@ impl EarlyLintPass for NonAsciiIdents {
.and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
if !*existing_is_ascii || !is_ascii {
cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
lint.build(&format!(
"identifier pair considered confusable between `{}` and `{}`",
existing_symbol, symbol
))
.span_label(
*existing_span,
"this is where the previous identifier occurred",
)
.emit();
lint.build(fluent::lint::confusable_identifier_pair)
.set_arg("existing_sym", *existing_symbol)
.set_arg("sym", symbol)
.span_label(*existing_span, fluent::lint::label)
.emit();
});
}
if *existing_is_ascii && !is_ascii {
@ -326,18 +323,20 @@ impl EarlyLintPass for NonAsciiIdents {
for ((sp, ch_list), script_set) in lint_reports {
cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
let message = format!(
"the usage of Script Group `{}` in this crate consists solely of mixed script confusables",
script_set);
let mut note = "the usage includes ".to_string();
let mut includes = String::new();
for (idx, ch) in ch_list.into_iter().enumerate() {
if idx != 0 {
note += ", ";
includes += ", ";
}
let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
note += &char_info;
includes += &char_info;
}
lint.build(&message).note(&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 rustc_ast as ast;
use rustc_errors::{pluralize, Applicability};
use rustc_errors::{fluent, Applicability};
use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::lint::in_external_macro;
@ -120,9 +120,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
}
cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
let mut l = lint.build("panic message is not a string literal");
l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol));
l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
let mut l = lint.build(fluent::lint::non_fmt_panic);
l.set_arg("name", symbol);
l.note(fluent::lint::note);
l.note(fluent::lint::more_info_note);
if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from.
l.emit();
@ -130,10 +131,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
}
if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`.
l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol).as_str());
l.note(fluent::lint::supports_fmt_note);
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
l.multipart_suggestion(
"remove the `format!(..)` macro call",
fluent::lint::supports_fmt_suggestion,
vec![
(arg_span.until(open.shrink_to_hi()), "".into()),
(close.until(arg_span.shrink_to_hi()), "".into()),
@ -153,12 +154,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
);
let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
}) == Some(true);
let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
}) == Some(true);
let display = is_str
|| cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
infcx
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
.may_apply()
}) == Some(true);
let debug = !display
&& cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
infcx
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
.may_apply()
}) == Some(true);
(display, debug)
});
@ -175,17 +182,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
if suggest_display {
l.span_suggestion_verbose(
arg_span.shrink_to_lo(),
"add a \"{}\" format string to Display the message",
fluent::lint::display_suggestion,
"\"{}\", ",
fmt_applicability,
);
} else if suggest_debug {
l.set_arg("ty", ty);
l.span_suggestion_verbose(
arg_span.shrink_to_lo(),
&format!(
"add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
ty,
),
fluent::lint::debug_suggestion,
"\"{:?}\", ",
fmt_applicability,
);
@ -193,15 +198,9 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
if suggest_panic_any {
if let Some((open, close, del)) = find_delimiters(cx, span) {
l.set_arg("already_suggested", suggest_display || suggest_debug);
l.multipart_suggestion(
&format!(
"{}use std::panic::panic_any instead",
if suggest_display || suggest_debug {
"or "
} else {
""
},
),
fluent::lint::panic_suggestion,
if del == '(' {
vec![(span.until(open), "std::panic::panic_any".into())]
} else {
@ -260,21 +259,19 @@ fn check_panic_str<'tcx>(
.collect(),
};
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
let mut l = lint.build(match n_arguments {
1 => "panic message contains an unused formatting placeholder",
_ => "panic message contains unused formatting placeholders",
});
l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
l.set_arg("count", n_arguments);
l.note(fluent::lint::note);
if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_hi(),
&format!("add the missing argument{}", pluralize!(n_arguments)),
fluent::lint::add_args_suggestion,
", ...",
Applicability::HasPlaceholders,
);
l.span_suggestion(
arg.span.shrink_to_lo(),
"or add a \"{}\" format string to use the message literally",
fluent::lint::add_fmt_suggestion,
"\"{}\", ",
Applicability::MachineApplicable,
);
@ -289,17 +286,15 @@ fn check_panic_str<'tcx>(
.map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
.collect()
});
let msg = match &brace_spans {
Some(v) if v.len() == 1 => "panic message contains a brace",
_ => "panic message contains braces",
};
let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
let mut l = lint.build(msg);
l.note("this message is not used as a format string, but will be in Rust 2021");
let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
l.set_arg("count", count);
l.note(fluent::lint::note);
if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_lo(),
"add a \"{}\" format string to use the message literally",
fluent::lint::suggestion,
"\"{}\", ",
Applicability::MachineApplicable,
);

View file

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

View file

@ -2,6 +2,7 @@ use crate::context::LintContext;
use crate::rustc_middle::ty::TypeFoldable;
use crate::LateContext;
use crate::LateLintPass;
use rustc_errors::fluent;
use rustc_hir::def::DefKind;
use rustc_hir::{Expr, ExprKind};
use rustc_middle::ty;
@ -80,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
) {
return;
}
let method = &call.ident.name;
let receiver = &elements[0];
let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
@ -90,19 +90,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
return;
}
let expr_span = expr.span;
let note = format!(
"the type `{:?}` which `{}` is being called on is the same as \
the type returned from `{}`, so the method call does not do \
anything and can be removed",
receiver_ty, method, method,
);
let span = expr_span.with_lo(receiver.span.hi());
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
let method = &call.ident.name;
let message =
format!("call to `.{}()` on a reference in this situation does nothing", &method,);
lint.build(&message).span_label(span, "unnecessary method call").note(&note).emit();
lint.build(fluent::lint::noop_method_call)
.set_arg("method", call.ident.name)
.set_arg("receiver_ty", receiver_ty)
.span_label(span, fluent::lint::label)
.note(fluent::lint::note)
.emit();
});
}
}

View file

@ -1,5 +1,5 @@
use crate::{LateContext, LateLintPass, LintContext};
use rustc_errors::Applicability;
use rustc_errors::{fluent, Applicability};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
@ -30,10 +30,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
}
if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| {
lint.build(&format!("passing `{}` by reference", t))
lint.build(fluent::lint::pass_by_value)
.set_arg("ty", t.clone())
.span_suggestion(
ty.span,
"try passing by value",
fluent::lint::suggestion,
t,
// Changing type of function argument
Applicability::MaybeIncorrect,

View file

@ -1,6 +1,6 @@
use crate::{EarlyContext, EarlyLintPass, LintContext};
use rustc_ast::{Block, StmtKind};
use rustc_errors::Applicability;
use rustc_errors::{fluent, Applicability};
use rustc_span::Span;
declare_lint! {
@ -49,12 +49,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
}
cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
let (msg, rem) = if multiple {
("unnecessary trailing semicolons", "remove these semicolons")
} else {
("unnecessary trailing semicolon", "remove this semicolon")
};
lint.build(msg).span_suggestion(span, rem, "", Applicability::MaybeIncorrect).emit();
lint.build(fluent::lint::redundant_semicolons)
.set_arg("multiple", multiple)
.span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect)
.emit();
});
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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
/// with the argument order swapped.
///
/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
/// requirements of `T`. The initialization state is preserved exactly.
///
/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
///
/// # Safety
@ -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`
/// to a temporary array and then copied from the array to `dst`.
///
/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
/// requirements of `T`. The initialization state is preserved exactly.
///
/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
///
/// # Safety

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
/// deinitializing either.
///
/// But for the following two exceptions, this function is semantically
/// But for the following exceptions, this function is semantically
/// equivalent to [`mem::swap`]:
///
/// * It operates on raw pointers instead of references. When references are
@ -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
/// in the second example below.
///
/// * The operation is "untyped" in the sense that data may be uninitialized or otherwise violate
/// the requirements of `T`. The initialization state is preserved exactly.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
@ -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
/// beginning at `x` and `y`. The two regions must *not* overlap.
///
/// The operation is "untyped" in the sense that data may be uninitialized or otherwise violate the
/// requirements of `T`. The initialization state is preserved exactly.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
@ -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>()
&& mem::size_of::<T>() % mem::size_of::<$ChunkTy>() == 0
{
let x: *mut MaybeUninit<$ChunkTy> = x.cast();
let y: *mut MaybeUninit<$ChunkTy> = y.cast();
let x: *mut $ChunkTy = x.cast();
let y: *mut $ChunkTy = y.cast();
let count = count * (mem::size_of::<T>() / mem::size_of::<$ChunkTy>());
// SAFETY: these are the same bytes that the caller promised were
// ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s.
// The `if` condition above ensures that we're not violating
// alignment requirements, and that the division is exact so
// that we don't lose any bytes off the end.
return unsafe { swap_nonoverlapping_simple(x, y, count) };
return unsafe { swap_nonoverlapping_simple_untyped(x, y, count) };
}
};
}
@ -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
unsafe { swap_nonoverlapping_simple(x, y, count) }
unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }
}
/// 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.
#[inline]
#[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;
while i < count {
let x: &mut T =
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
unsafe { &mut *x.add(i) };
let y: &mut T =
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
// and it's distinct from `x` since the ranges are non-overlapping
unsafe { &mut *y.add(i) };
mem::swap_simple(x, y);
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
let x = unsafe { &mut *x.add(i) };
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
// and it's distinct from `x` since the ranges are non-overlapping
let y = unsafe { &mut *y.add(i) };
mem::swap_simple::<MaybeUninit<T>>(x, y);
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]
fn test_const_copy() {
const {

View file

@ -1739,6 +1739,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
/* Media Queries */
/*
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY;
If you update this line, then you also need to update the line with the same warning
in storage.js plus the media query with (max-width: 700px)
*/
@media (min-width: 701px) {
/* In case there is no documentation before a code block, we need to add some margin at the top
to prevent an overlay between the "collapse toggle" and the information tooltip.
@ -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) {
/* 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

View file

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

View file

@ -9,6 +9,11 @@ const darkThemes = ["dark", "ayu"];
window.currentTheme = document.getElementById("themeStyle");
window.mainTheme = document.getElementById("mainThemeStyle");
// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
// If you update this line, then you also need to update the two media queries with the same
// warning in rustdoc.css
window.RUSTDOC_MOBILE_BREAKPOINT = 701;
const settingsDataset = (function() {
const settingsElement = document.getElementById("default-settings");
if (settingsElement === null) {

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`.
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.
show-text: true
@ -221,3 +232,23 @@ click: "#sidebar-toggle"
wait-for-css: (".sidebar", {"width": "0px"})
// The "scrollTop" property should be the same.
assert-window-property: {"pageYOffset": "2519"}
// We now check that opening the sidebar and clicking a link will close it.
// The behavior here on mobile is different than the behavior on desktop,
// but common sense dictates that if you have a list of files that fills the entire screen, and
// you click one of them, you probably want to actually see the file's contents, and not just
// make it the current selection.
click: "#sidebar-toggle"
wait-for-css: ("#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;
/// [mod@std::env] [g]
// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports.
// Until then, comment out the `htmldocck` test.
// This test still does something; namely check that no incorrect errors are emitted when
// documenting the re-export.
// @has outer/index.html
// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env"
// @ has - '//a[@href="fn.f.html"]' "g"
// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
// @has - '//a[@href="fn.f.html"]' "g"
pub use f as g;
// FIXME: same as above
/// [std::env]
extern crate self as _;
// Make sure the documentation is actually correct by documenting an inlined re-export
/// [mod@std::env]
// @has outer/fn.f.html

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
|
LL | #[doc(keyword = "tadam")]

View file

@ -1,6 +1,8 @@
// check-fail
// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
// normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr"
// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
// the test is just ignored on stable and beta:

View file

@ -1,5 +1,5 @@
error: `#[derive(SessionDiagnostic)]` can only be used on structs
--> $DIR/diagnostic-derive.rs:37:1
--> $DIR/diagnostic-derive.rs:39:1
|
LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
LL | |
@ -10,13 +10,13 @@ LL | | }
| |_^
error: `#[error = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:46:1
--> $DIR/diagnostic-derive.rs:48:1
|
LL | #[error = "E0123"]
| ^^^^^^^^^^^^^^^^^^
error: `#[nonsense(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:51:1
--> $DIR/diagnostic-derive.rs:53:1
|
LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -24,7 +24,7 @@ LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
= help: only `error`, `warning`, `help` and `note` are valid attributes
error: diagnostic kind not specified
--> $DIR/diagnostic-derive.rs:51:1
--> $DIR/diagnostic-derive.rs:53:1
|
LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
LL | |
@ -36,7 +36,7 @@ LL | | struct InvalidStructAttr {}
= help: use the `#[error(...)]` attribute to create an error
error: `#[error("...")]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:58:9
--> $DIR/diagnostic-derive.rs:60:9
|
LL | #[error("E0123")]
| ^^^^^^^
@ -44,7 +44,7 @@ LL | #[error("E0123")]
= help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:58:1
--> $DIR/diagnostic-derive.rs:60:1
|
LL | / #[error("E0123")]
LL | |
@ -55,7 +55,7 @@ LL | | struct InvalidLitNestedAttr {}
= help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
error: `#[error(nonsense(...))]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:69:9
--> $DIR/diagnostic-derive.rs:71:9
|
LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
| ^^^^^^^^^^^^^^^
@ -63,7 +63,7 @@ LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
= help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:69:1
--> $DIR/diagnostic-derive.rs:71:1
|
LL | / #[error(nonsense("foo"), code = "E0123", slug = "foo")]
LL | |
@ -74,7 +74,7 @@ LL | | struct InvalidNestedStructAttr1 {}
= help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
error: `#[error(nonsense = ...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:75:9
--> $DIR/diagnostic-derive.rs:77:9
|
LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
| ^^^^^^^^^^^^^^^^
@ -82,7 +82,7 @@ LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
= help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:75:1
--> $DIR/diagnostic-derive.rs:77:1
|
LL | / #[error(nonsense = "...", code = "E0123", slug = "foo")]
LL | |
@ -93,7 +93,7 @@ LL | | struct InvalidNestedStructAttr2 {}
= help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
error: `#[error(nonsense = ...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:81:9
--> $DIR/diagnostic-derive.rs:83:9
|
LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
| ^^^^^^^^^^^^
@ -101,7 +101,7 @@ LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
= help: first argument of the attribute should be the diagnostic slug
error: diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:81:1
--> $DIR/diagnostic-derive.rs:83:1
|
LL | / #[error(nonsense = 4, code = "E0123", slug = "foo")]
LL | |
@ -112,7 +112,7 @@ LL | | struct InvalidNestedStructAttr3 {}
= help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
error: `#[error(slug = ...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:87:59
--> $DIR/diagnostic-derive.rs:89:59
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
| ^^^^^^^^^^^^
@ -120,103 +120,103 @@ LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
= help: only `code` is a valid nested attributes following the slug
error: `#[suggestion = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:94:5
--> $DIR/diagnostic-derive.rs:96:5
|
LL | #[suggestion = "bar"]
| ^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/diagnostic-derive.rs:101:1
--> $DIR/diagnostic-derive.rs:103:1
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/diagnostic-derive.rs:100:1
--> $DIR/diagnostic-derive.rs:102:1
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/diagnostic-derive.rs:101:1
--> $DIR/diagnostic-derive.rs:103:1
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/diagnostic-derive.rs:100:1
--> $DIR/diagnostic-derive.rs:102:1
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/diagnostic-derive.rs:101:50
--> $DIR/diagnostic-derive.rs:103:50
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^
|
note: previously specified here
--> $DIR/diagnostic-derive.rs:100:50
--> $DIR/diagnostic-derive.rs:102:50
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^
error: specified multiple times
--> $DIR/diagnostic-derive.rs:109:1
--> $DIR/diagnostic-derive.rs:111:1
|
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/diagnostic-derive.rs:108:1
--> $DIR/diagnostic-derive.rs:110:1
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/diagnostic-derive.rs:109:1
--> $DIR/diagnostic-derive.rs:111:1
|
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/diagnostic-derive.rs:108:1
--> $DIR/diagnostic-derive.rs:110:1
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/diagnostic-derive.rs:109:52
--> $DIR/diagnostic-derive.rs:111:52
|
LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
| ^^^^^^^
|
note: previously specified here
--> $DIR/diagnostic-derive.rs:108:50
--> $DIR/diagnostic-derive.rs:110:50
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^
error: specified multiple times
--> $DIR/diagnostic-derive.rs:116:66
--> $DIR/diagnostic-derive.rs:118:66
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
| ^^^^^^^
|
note: previously specified here
--> $DIR/diagnostic-derive.rs:116:50
--> $DIR/diagnostic-derive.rs:118:50
|
LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
| ^^^^^^^
error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:121:43
--> $DIR/diagnostic-derive.rs:123:43
|
LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostic kind not specified
--> $DIR/diagnostic-derive.rs:126:1
--> $DIR/diagnostic-derive.rs:128:1
|
LL | struct KindNotProvided {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -224,7 +224,7 @@ LL | struct KindNotProvided {}
= help: use the `#[error(...)]` attribute to create an error
error: diagnostic slug not specified
--> $DIR/diagnostic-derive.rs:129:1
--> $DIR/diagnostic-derive.rs:131:1
|
LL | / #[error(code = "E0456")]
LL | |
@ -234,13 +234,13 @@ LL | | struct SlugNotProvided {}
= help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
--> $DIR/diagnostic-derive.rs:140:5
--> $DIR/diagnostic-derive.rs:142:5
|
LL | #[primary_span]
| ^^^^^^^^^^^^^^^
error: `#[nonsense]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:148:5
--> $DIR/diagnostic-derive.rs:150:5
|
LL | #[nonsense]
| ^^^^^^^^^^^
@ -248,19 +248,19 @@ LL | #[nonsense]
= help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes
error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
--> $DIR/diagnostic-derive.rs:165:5
--> $DIR/diagnostic-derive.rs:167:5
|
LL | #[label(typeck::label)]
| ^^^^^^^^^^^^^^^^^^^^^^^
error: `name` doesn't refer to a field on this type
--> $DIR/diagnostic-derive.rs:173:45
--> $DIR/diagnostic-derive.rs:175:45
|
LL | #[suggestion(typeck::suggestion, code = "{name}")]
| ^^^^^^^^
error: invalid format string: expected `'}'` but string was terminated
--> $DIR/diagnostic-derive.rs:178:16
--> $DIR/diagnostic-derive.rs:180:16
|
LL | #[derive(SessionDiagnostic)]
| - ^ expected `'}'` in format string
@ -271,7 +271,7 @@ LL | #[derive(SessionDiagnostic)]
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid format string: unmatched `}` found
--> $DIR/diagnostic-derive.rs:188:15
--> $DIR/diagnostic-derive.rs:190:15
|
LL | #[derive(SessionDiagnostic)]
| ^ unmatched `}` in format string
@ -280,13 +280,13 @@ LL | #[derive(SessionDiagnostic)]
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
--> $DIR/diagnostic-derive.rs:208:5
--> $DIR/diagnostic-derive.rs:210:5
|
LL | #[label(typeck::label)]
| ^^^^^^^^^^^^^^^^^^^^^^^
error: `#[suggestion(nonsense = ...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:233:18
--> $DIR/diagnostic-derive.rs:235:18
|
LL | #[suggestion(nonsense = "bar")]
| ^^^^^^^^^^^^^^^^
@ -294,7 +294,7 @@ LL | #[suggestion(nonsense = "bar")]
= help: only `message`, `code` and `applicability` are valid field attributes
error: `#[suggestion(msg = ...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:241:18
--> $DIR/diagnostic-derive.rs:243:18
|
LL | #[suggestion(msg = "bar")]
| ^^^^^^^^^^^
@ -302,7 +302,7 @@ LL | #[suggestion(msg = "bar")]
= help: only `message`, `code` and `applicability` are valid field attributes
error: wrong field type for suggestion
--> $DIR/diagnostic-derive.rs:263:5
--> $DIR/diagnostic-derive.rs:265:5
|
LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
LL | |
@ -312,7 +312,7 @@ LL | | suggestion: Applicability,
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
--> $DIR/diagnostic-derive.rs:278:5
--> $DIR/diagnostic-derive.rs:280:5
|
LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
LL | |
@ -320,7 +320,7 @@ LL | | suggestion: (Span, Span, Applicability),
| |___________________________________________^
error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
--> $DIR/diagnostic-derive.rs:286:5
--> $DIR/diagnostic-derive.rs:288:5
|
LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")]
LL | |
@ -328,72 +328,66 @@ LL | | suggestion: (Applicability, Applicability, Span),
| |____________________________________________________^
error: `#[label = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:294:5
--> $DIR/diagnostic-derive.rs:296:5
|
LL | #[label = "bar"]
| ^^^^^^^^^^^^^^^^
error: applicability cannot be set in both the field and attribute
--> $DIR/diagnostic-derive.rs:445:52
--> $DIR/diagnostic-derive.rs:447:52
|
LL | #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: invalid applicability
--> $DIR/diagnostic-derive.rs:453:52
--> $DIR/diagnostic-derive.rs:455:52
|
LL | #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:516:5
--> $DIR/diagnostic-derive.rs:518:5
|
LL | #[label(typeck::label, foo)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:524:5
--> $DIR/diagnostic-derive.rs:526:5
|
LL | #[label(typeck::label, foo = "...")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(...)]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:532:5
--> $DIR/diagnostic-derive.rs:534:5
|
LL | #[label(typeck::label, foo("..."))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: cannot find attribute `nonsense` in this scope
--> $DIR/diagnostic-derive.rs:51:3
--> $DIR/diagnostic-derive.rs:53:3
|
LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
| ^^^^^^^^
error: cannot find attribute `nonsense` in this scope
--> $DIR/diagnostic-derive.rs:148:7
--> $DIR/diagnostic-derive.rs:150:7
|
LL | #[nonsense]
| ^^^^^^^^
error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent`
--> $DIR/diagnostic-derive.rs:64:9
--> $DIR/diagnostic-derive.rs:66:9
|
LL | #[error(nonsense, code = "E0123")]
| ^^^^^^^^ not found in `rustc_errors::fluent`
error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
--> $DIR/diagnostic-derive.rs:338:10
--> $DIR/diagnostic-derive.rs:340:10
|
LL | #[derive(SessionDiagnostic)]
| ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
|
= help: the following other types implement trait `IntoDiagnosticArg`:
&'a str
Ident
String
Symbol
rustc_middle::ty::Ty<'tcx>
usize
= help: normalized in stderr
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:538:19
|

View file

@ -5,9 +5,9 @@ LL | panic!({ "foo" });
| ^^^^^^^^^
|
= note: `#[warn(non_fmt_panics)]` on by default
= note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
= note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
= note: for more information, see <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" });
| +++++

View file

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

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