summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_lint
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_lint
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_lint')
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/messages.ftl713
-rw-r--r--compiler/rustc_lint/src/builtin.rs105
-rw-r--r--compiler/rustc_lint/src/context.rs104
-rw-r--r--compiler/rustc_lint/src/drop_forget_useless.rs164
-rw-r--r--compiler/rustc_lint/src/early.rs2
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs2
-rw-r--r--compiler/rustc_lint/src/errors.rs2
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/internal.rs87
-rw-r--r--compiler/rustc_lint/src/late.rs10
-rw-r--r--compiler/rustc_lint/src/levels.rs14
-rw-r--r--compiler/rustc_lint/src/lib.rs8
-rw-r--r--compiler/rustc_lint/src/lints.rs53
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs8
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs117
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/types.rs6
-rw-r--r--compiler/rustc_lint/src/unused.rs95
20 files changed, 961 insertions, 538 deletions
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index abe61406c..539eea3d8 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -11,6 +11,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_target = { path = "../rustc_target" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index db15b176d..0fa67cdb3 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -5,6 +5,202 @@ lint_array_into_iter =
.use_explicit_into_iter_suggestion =
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+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_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_bad_attribute_argument = bad attribute argument
+
+lint_bad_opt_access = {$msg}
+
+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_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_asm_labels = avoid using named labels in inline assembly
+
+lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
+
+lint_builtin_clashing_extern_diff_name = `{$this}` 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_clashing_extern_same_name = `{$this}` redeclared with a different signature
+ .previous_decl_label = `{$orig}` previously declared here
+ .mismatch_label = this signature doesn't match the previous declaration
+lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
+ .suggestion = try a static value
+
+lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
+lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
+lint_builtin_deprecated_attr_default_suggestion = remove this attribute
+
+lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
+ .msg_suggestion = {$msg}
+ .default_suggestion = remove this attribute
+lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used.
+lint_builtin_deref_nullptr = dereferencing a null pointer
+ .label = this code causes undefined behavior when executed
+
+lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
+ .suggestion = use `..=` for an inclusive range
+
+lint_builtin_explicit_outlives = outlives requirements can be inferred
+ .suggestion = remove {$count ->
+ [one] this bound
+ *[other] these bounds
+ }
+
+lint_builtin_export_name_fn = declaration of a function with `export_name`
+lint_builtin_export_name_method = declaration of a method with `export_name`
+
+lint_builtin_export_name_static = declaration of a static with `export_name`
+lint_builtin_impl_unsafe_method = implementation of an `unsafe` method
+
+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_keyword_idents = `{$kw}` is a keyword in the {$next} edition
+ .suggestion = you can use a raw identifier to stay compatible
+
+lint_builtin_link_section_fn = declaration of a function with `link_section`
+
+lint_builtin_link_section_static = declaration of a static with `link_section`
+
+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_missing_doc = missing documentation for {$article} {$desc}
+
+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_no_mangle_fn = declaration of a `no_mangle` function
+lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled
+ .suggestion = remove this attribute
+
+lint_builtin_no_mangle_method = declaration of a `no_mangle` method
+lint_builtin_no_mangle_static = declaration of a `no_mangle` static
+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_special_module_name_used_lib = found module declaration for lib.rs
+ .note = lib.rs is the root of this crate's library target
+ .help = to refer to it from other targets, use the library's name as the path
+
+lint_builtin_special_module_name_used_main = found module declaration for main.rs
+ .note = a binary crate cannot be used as library
+
+lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters
+
+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_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_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_unexpected_cli_config_name = unexpected `{$name}` as condition name
+ .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
+ .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+lint_builtin_unnameable_test_items = cannot test inner items
+
+lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
+lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+
+lint_builtin_unpermitted_type_init_uninit = the type `{$ty}` does not permit being left uninitialized
+
+lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
+lint_builtin_unreachable_pub = unreachable `pub` {$what}
+ .suggestion = consider restricting its visibility
+ .help = or consider exporting it for use by other crates
+
+lint_builtin_unsafe_block = usage of an `unsafe` block
+
+lint_builtin_unsafe_impl = implementation of an `unsafe` trait
+
+lint_builtin_unsafe_trait = declaration of an `unsafe` trait
+
+lint_builtin_unstable_features = unstable feature
+
+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_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
+ .suggestion = use `loop`
+
+lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
+
+lint_check_name_unknown = unknown lint: `{$lint_name}`
+ .help = did you mean: `{$suggestion}`
+
+lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
+
+lint_check_name_warning = {$msg}
+
+lint_command_line_source = `forbid` lint level was set on command line
+
+lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
+ .label = this is where the previous identifier occurred
+
+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_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
+ .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
+
+lint_default_source = `forbid` lint level is the default for {$id}
+
+lint_deprecated_lint_name =
+ lint name `{$name}` is deprecated and may not have an effect in the future.
+ .suggestion = change it to
+
+lint_diag_out_of_impl =
+ diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
+
+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_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_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
+
+lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
+
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.
@@ -24,41 +220,12 @@ lint_for_loops_over_fallibles =
.use_while_let = to check pattern in a loop use `while let`
.use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
-lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
- .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
- .function_label = this function returns `()`, which is likely not what you wanted
- .argument_label = called `Iterator::map` with callable that returns `()`
- .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
- .suggestion = you might have meant to use `Iterator::for_each`
-
-lint_non_binding_let_on_sync_lock =
- non-binding let on a synchronization lock
-
-lint_non_binding_let_on_drop_type =
- non-binding let on a type that implements `Drop`
-
-lint_non_binding_let_suggestion =
- consider binding to an unused variable to avoid immediately dropping the value
-
-lint_non_binding_let_multi_suggestion =
- consider immediately dropping the value
-
-lint_deprecated_lint_name =
- lint name `{$name}` is deprecated and may not have an effect in the future.
- .suggestion = change it to
-
-lint_renamed_or_removed_lint = {$msg}
- .suggestion = use the new name
-
-lint_unknown_lint =
- unknown lint: `{$name}`
- .suggestion = did you mean
-
-lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
-
-lint_unknown_gated_lint =
- unknown lint: `{$name}`
- .note = the `{$name}` lint is unstable
+lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
+lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
.label = this {$label} contains {$count ->
@@ -73,54 +240,111 @@ lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of
.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_identifier_non_ascii_char = identifier contains non-ASCII characters
-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_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
-lint_tykind_kind = usage of `ty::TyKind::<kind>`
- .suggestion = try using `ty::<kind>` directly
+lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
-lint_tykind = usage of `ty::TyKind`
- .help = try using `Ty` instead
+lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
+ .label = not FFI-safe
+ .note = the type is defined here
-lint_ty_qualified = usage of qualified `ty::{$ty}`
- .suggestion = try importing it and using it unqualified
+lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI
-lint_lintpass_by_hand = implementing `LintPass` by hand
- .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
+lint_improper_ctypes_array_help = consider passing a pointer to the array
-lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]`
- .help = only existing keywords are allowed in core/std
+lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
+lint_improper_ctypes_box = box cannot be represented as a single pointer
-lint_diag_out_of_impl =
- diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
+lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
-lint_untranslatable_diag = diagnostics should be created using translatable messages
+lint_improper_ctypes_char_reason = the `char` type has no C equivalent
+lint_improper_ctypes_dyn = trait objects have no C equivalent
-lint_bad_opt_access = {$msg}
+lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
-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_improper_ctypes_enum_repr_help =
+ consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
-lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+lint_improper_ctypes_enum_repr_reason = enum has no representation hint
+lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead
-lint_identifier_non_ascii_char = identifier contains non-ASCII characters
+lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention
+lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive
+lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants
-lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
+lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
-lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
- .label = this is where the previous identifier occurred
+lint_improper_ctypes_opaque = opaque types have no C equivalent
+
+lint_improper_ctypes_slice_help = consider using a raw pointer instead
+
+lint_improper_ctypes_slice_reason = slices have no C equivalent
+lint_improper_ctypes_str_help = consider using `*const u8` and a length instead
+
+lint_improper_ctypes_str_reason = string slices have no C equivalent
+lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct
+
+lint_improper_ctypes_struct_fieldless_reason = this struct has no fields
+lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+
+lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout
+lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive
+lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields
+
+lint_improper_ctypes_tuple_help = consider using a struct instead
+
+lint_improper_ctypes_tuple_reason = tuples have unspecified layout
+lint_improper_ctypes_union_fieldless_help = consider adding a member to this union
+
+lint_improper_ctypes_union_fieldless_reason = this union has no fields
+lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+
+lint_improper_ctypes_union_layout_reason = this union has unspecified layout
+lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
+
+lint_lintpass_by_hand = implementing `LintPass` by hand
+ .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
+
+lint_malformed_attribute = malformed lint attribute input
+
+lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
+ .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+ .function_label = this function returns `()`, which is likely not what you wanted
+ .argument_label = called `Iterator::map` with callable that returns `()`
+ .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+ .suggestion = you might have meant to use `Iterator::for_each`
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_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+
+lint_node_source = `forbid` level set here
+ .note = {$reason}
+
+lint_non_binding_let_multi_suggestion =
+ consider immediately dropping the value
+
+lint_non_binding_let_on_drop_type =
+ non-binding let on a type that implements `Drop`
+
+lint_non_binding_let_on_sync_lock =
+ non-binding let on a synchronization lock
+
+lint_non_binding_let_suggestion =
+ consider binding to an unused variable to avoid immediately dropping the value
+
+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_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]`
+ .help = only existing keywords are allowed in core/std
+
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>
@@ -134,6 +358,14 @@ lint_non_fmt_panic = panic message is not a string literal
*[false] use
} std::panic::panic_any instead
+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_fmt_panic_unused =
panic message contains {$count ->
[one] an unused
@@ -149,18 +381,6 @@ lint_non_fmt_panic_unused =
}
.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
@@ -177,29 +397,13 @@ lint_noop_method_call = call to `.{$method}()` on a reference in this situation
.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}`
+lint_only_cast_u8_to_char = only `u8` can be cast into `char`
+ .suggestion = use a `char` literal instead
-lint_range_use_inclusive_range = use an inclusive range instead
+lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
+ .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
+lint_opaque_hidden_inferred_bound_sugg = add this bound
lint_overflowing_bin_hex = literal out of range for `{$ty}`
.negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
@@ -212,96 +416,90 @@ 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_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_improper_ctypes_opaque = opaque types have no C equivalent
+lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
+ .label = overruled by previous forbid
-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_pass_by_value = passing `{$ty}` by reference
+ .suggestion = try passing by value
-lint_improper_ctypes_tuple_reason = tuples have unspecified layout
-lint_improper_ctypes_tuple_help = consider using a struct instead
+lint_path_statement_drop = path statement drops value
+ .suggestion = use `drop` to clarify the intent
-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_path_statement_no_effect = path statement with no effect
-lint_improper_ctypes_dyn = trait objects have no C equivalent
+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_improper_ctypes_slice_reason = slices have no C equivalent
-lint_improper_ctypes_slice_help = consider using a raw pointer instead
+lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
-lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI
+lint_range_use_inclusive_range = use an inclusive range instead
-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_reason_must_be_string_literal = reason must be a string literal
-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_reason_must_come_last = reason in lint attribute must come last
-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_redundant_semicolons =
+ unnecessary trailing {$multiple ->
+ [true] semicolons
+ *[false] semicolon
+ }
+ .suggestion = remove {$multiple ->
+ [true] these semicolons
+ *[false] this semicolon
+ }
-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_renamed_or_removed_lint = {$msg}
+ .suggestion = use the new name
-lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive
-lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
+lint_requested_level = requested on the command line with `{$level} {$lint_name}`
-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_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
+ .label = target type is set here
-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_suspicious_double_ref_clone =
+ using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type
-lint_improper_ctypes_box = box cannot be represented as a single pointer
+lint_suspicious_double_ref_deref =
+ using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
-lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
+lint_trivial_untranslatable_diag = diagnostic with static strings only
-lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields
+lint_ty_qualified = usage of qualified `ty::{$ty}`
+ .suggestion = try importing it and using it unqualified
-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_tykind = usage of `ty::TyKind`
+ .help = try using `Ty` instead
-lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
+lint_tykind_kind = usage of `ty::TyKind::<kind>`
+ .suggestion = try using `ty::<kind>` directly
-lint_variant_size_differences =
- enum variant is more than three times larger ({$largest} bytes) than the next largest
+lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
+ .label = this function will not propagate the caller location
-lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering
- .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+lint_unknown_gated_lint =
+ unknown lint: `{$name}`
+ .note = the `{$name}` lint is unstable
-lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
- .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+lint_unknown_lint =
+ unknown lint: `{$name}`
+ .suggestion = did you mean
-lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering
- .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
+lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
+ .help = add `#![register_tool({$tool_name})]` to the crate root
-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_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
-lint_unused_op = unused {$op} that must be used
- .label = the {$op} produces a value
- .suggestion = use `let _ = ...` to ignore the resulting value
+lint_untranslatable_diag = diagnostics should be created using translatable messages
-lint_unused_result = unused result of type `{$ty}`
+lint_unused_allocation = unnecessary allocation, use `&` instead
+lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
lint_unused_closure =
unused {$pre}{$count ->
@@ -310,203 +508,28 @@ lint_unused_closure =
}{$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_comparisons = comparison is useless due to type limits
lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
.suggestion = use `let _ = ...` to ignore the resulting value
-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}
- .msg_suggestion = {$msg}
- .default_suggestion = remove this attribute
-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_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
- .label = this function will not propagate the caller location
-
-lint_builtin_unreachable_pub = unreachable `pub` {$what}
- .suggestion = consider restricting its visibility
- .help = or consider exporting it for use by other crates
-
-lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
- .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
-
-lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
- .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
-
-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_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
-lint_builtin_unpermitted_type_init_unint = the type `{$ty}` does not permit being left uninitialized
-
-lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
-lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
-
-lint_builtin_clashing_extern_same_name = `{$this}` 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}` 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
-
-lint_builtin_special_module_name_used_lib = found module declaration for lib.rs
- .note = lib.rs is the root of this crate's library target
- .help = to refer to it from other targets, use the library's name as the path
-
-lint_builtin_special_module_name_used_main = found module declaration for main.rs
- .note = a binary crate cannot be used as library
-
-lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
- .label = target type is set here
-
-lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
- .label = overruled by previous forbid
-
-lint_default_source = `forbid` lint level is the default for {$id}
-
-lint_node_source = `forbid` level set here
- .note = {$reason}
-
-lint_command_line_source = `forbid` lint level was set on command line
-
-lint_malformed_attribute = malformed lint attribute input
-
-lint_bad_attribute_argument = bad attribute argument
-
-lint_reason_must_be_string_literal = reason must be a string literal
-
-lint_reason_must_come_last = reason in lint attribute must come last
-
-lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
- .help = add `#![register_tool({$tool_name})]` to the crate root
-
-lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
-
-lint_requested_level = requested on the command line with `{$level} {$lint_name}`
-
-lint_check_name_unknown = unknown lint: `{$lint_name}`
- .help = did you mean: `{$suggestion}`
-
-lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
+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_check_name_warning = {$msg}
+lint_unused_import_braces = braces around {$node} is unnecessary
-lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
+lint_unused_op = unused {$op} that must be used
+ .label = the {$op} produces a value
+ .suggestion = use `let _ = ...` to ignore the resulting value
-lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
- .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
+lint_unused_result = unused result of type `{$ty}`
-lint_opaque_hidden_inferred_bound_sugg = add this bound
+lint_variant_size_differences =
+ enum variant is more than three times larger ({$largest} bytes) than the next largest
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 6b387df78..85141836e 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -22,7 +22,7 @@
use crate::fluent_generated as fluent;
use crate::{
- errors::BuiltinEllpisisInclusiveRangePatterns,
+ errors::BuiltinEllipsisInclusiveRangePatterns,
lints::{
BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern,
BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
@@ -62,7 +62,9 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
+use rustc_session::config::ExpectedValues;
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
@@ -116,8 +118,7 @@ impl EarlyLintPass for WhileTrue {
#[inline]
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
if let ast::ExprKind::While(cond, _, label) = &e.kind
- && let cond = pierce_parens(cond)
- && let ast::ExprKind::Lit(token_lit) = cond.kind
+ && let ast::ExprKind::Lit(token_lit) = pierce_parens(cond).kind
&& let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
&& !cond.span.from_expansion()
{
@@ -166,10 +167,8 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
impl BoxPointers {
fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
for leaf in ty.walk() {
- if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
- if leaf_ty.is_box() {
- cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
- }
+ if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() {
+ cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
}
}
}
@@ -548,32 +547,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
- match it.kind {
- hir::ItemKind::Trait(..) => {
- // Issue #11592: traits are always considered exported, even when private.
- if cx.tcx.visibility(it.owner_id)
- == ty::Visibility::Restricted(
- cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(),
- )
- {
- return;
- }
- }
- hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::Macro(..)
- | hir::ItemKind::Mod(..)
- | hir::ItemKind::Enum(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Union(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::Static(..) => {}
-
- _ => return,
- };
+ // Previously the Impl and Use types have been excluded from missing docs,
+ // so we will continue to exclude them for compatibility.
+ //
+ // The documentation on `ExternCrate` is not used at the moment so no need to warn for it.
+ if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(_) =
+ it.kind
+ {
+ return;
+ }
let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
-
self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
}
@@ -631,7 +615,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
declare_lint! {
/// The `missing_copy_implementations` lint detects potentially-forgotten
- /// implementations of [`Copy`].
+ /// implementations of [`Copy`] for public types.
///
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
///
@@ -667,7 +651,9 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])
impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
+ if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
+ && cx.tcx.local_visibility(item.owner_id.def_id).is_public())
+ {
return;
}
let (def, ty) = match item.kind {
@@ -747,7 +733,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
declare_lint! {
/// The `missing_debug_implementations` lint detects missing
- /// implementations of [`fmt::Debug`].
+ /// implementations of [`fmt::Debug`] for public types.
///
/// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
///
@@ -786,7 +772,9 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
+ if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
+ && cx.tcx.local_visibility(item.owner_id.def_id).is_public())
+ {
return;
}
@@ -977,7 +965,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
}
- if attrs.peek().map_or(false, |next_attr| next_attr.is_doc_comment()) {
+ if attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) {
continue;
}
@@ -1463,6 +1451,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
// Bounds are respected for `type X = impl Trait`
return;
}
+ if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
+ // Bounds are respected for `type X = … Type::Inherent …`
+ return;
+ }
// There must not be a where clause
if type_alias_generics.predicates.is_empty() {
return;
@@ -1582,7 +1574,6 @@ declare_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
- use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::Clause;
use rustc_middle::ty::PredicateKind::*;
@@ -1711,13 +1702,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}
}
- let (parenthesise, endpoints) = match &pat.kind {
+ let (parentheses, endpoints) = match &pat.kind {
PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
_ => (false, matches_ellipsis_pat(pat)),
};
if let Some((start, end, join)) = endpoints {
- if parenthesise {
+ if parentheses {
self.node_id = Some(pat.id);
let end = expr_to_string(&end);
let replace = match start {
@@ -1725,7 +1716,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
None => format!("&(..={})", end),
};
if join.edition() >= Edition::Edition2021 {
- cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+ cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns {
span: pat.span,
suggestion: pat.span,
replace,
@@ -1743,7 +1734,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
} else {
let replace = "..=";
if join.edition() >= Edition::Edition2021 {
- cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+ cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns {
span: pat.span,
suggestion: join,
replace: replace.to_string(),
@@ -1899,8 +1890,8 @@ declare_lint_pass!(
struct UnderMacro(bool);
impl KeywordIdents {
- fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
- for tt in tokens.into_trees() {
+ fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
+ for tt in tokens.trees() {
match tt {
// Only report non-raw idents.
TokenTree::Token(token, _) => {
@@ -1961,10 +1952,10 @@ impl KeywordIdents {
impl EarlyLintPass for KeywordIdents {
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
- self.check_tokens(cx, mac_def.body.tokens.clone());
+ self.check_tokens(cx, &mac_def.body.tokens);
}
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
- self.check_tokens(cx, mac.args.tokens.clone());
+ self.check_tokens(cx, &mac.args.tokens);
}
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
self.check_ident_token(cx, UnderMacro(false), ident);
@@ -2560,7 +2551,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
.subst(cx.tcx, substs)
.apply_any_module(cx.tcx, cx.param_env)
{
- // Entirely skip uninhbaited variants.
+ // Entirely skip uninhabited variants.
Some(false) => return None,
// Forward the others, but remember which ones are definitely inhabited.
Some(true) => true,
@@ -2628,7 +2619,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
let msg = match init {
InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
- InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_unint,
+ InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit,
};
let sub = BuiltinUnpermittedTypeInitSub { err };
cx.emit_spanned_lint(
@@ -2919,6 +2910,7 @@ impl ClashingExternDeclarations {
| (Generator(..), Generator(..))
| (GeneratorWitness(..), GeneratorWitness(..))
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
+ | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
// These definitely should have been caught above.
@@ -3308,16 +3300,15 @@ impl EarlyLintPass for UnexpectedCfgs {
let cfg = &cx.sess().parse_sess.config;
let check_cfg = &cx.sess().parse_sess.check_config;
for &(name, value) in cfg {
- if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
- cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
- name,
- });
- }
- if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
- cx.emit_lint(
- UNEXPECTED_CFGS,
- BuiltinUnexpectedCliConfigValue { name, value },
- );
+ match check_cfg.expecteds.get(&name) {
+ Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
+ let value = value.unwrap_or(kw::Empty);
+ cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigValue { name, value });
+ }
+ None if check_cfg.exhaustive_names => {
+ cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { name });
+ }
+ _ => { /* expected */ }
}
}
}
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 626c09fea..1d0c43e95 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -36,6 +36,7 @@ use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_session::config::ExpectedValues;
use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
@@ -48,9 +49,9 @@ use std::cell::Cell;
use std::iter;
use std::slice;
-type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync;
+type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
type LateLintPassFactory =
- dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync;
+ dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
/// Information about the registered lints.
///
@@ -168,7 +169,7 @@ impl LintStore {
pub fn register_early_pass(
&mut self,
- pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
+ pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
) {
self.early_passes.push(Box::new(pass));
}
@@ -181,7 +182,7 @@ impl LintStore {
/// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518)
pub fn register_pre_expansion_pass(
&mut self,
- pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
+ pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
) {
self.pre_expansion_passes.push(Box::new(pass));
}
@@ -190,8 +191,8 @@ impl LintStore {
&mut self,
pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+ 'static
- + sync::Send
- + sync::Sync,
+ + sync::DynSend
+ + sync::DynSync,
) {
self.late_passes.push(Box::new(pass));
}
@@ -200,8 +201,8 @@ impl LintStore {
&mut self,
pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+ 'static
- + sync::Send
- + sync::Sync,
+ + sync::DynSend
+ + sync::DynSync,
) {
self.late_module_passes.push(Box::new(pass));
}
@@ -616,7 +617,7 @@ pub trait LintContext: Sized {
1 => ("an ", ""),
_ => ("", "s"),
};
- db.span_label(span, &format!(
+ db.span_label(span, format!(
"this comment contains {}invisible unicode text flow control codepoint{}",
an,
s,
@@ -680,12 +681,12 @@ pub trait LintContext: Sized {
);
}
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
- db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
+ db.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect);
}
BuiltinLintDiagnostics::UnusedImports(message, replaces, in_test_module) => {
if !replaces.is_empty() {
db.tool_only_multipart_suggestion(
- &message,
+ message,
replaces,
Applicability::MachineApplicable,
);
@@ -720,13 +721,13 @@ pub trait LintContext: Sized {
}
BuiltinLintDiagnostics::MissingAbi(span, default_abi) => {
db.span_label(span, "ABI should be specified here");
- db.help(&format!("the default ABI is {}", default_abi.name()));
+ db.help(format!("the default ABI is {}", default_abi.name()));
}
BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
db.span_label(span, "the attribute is introduced here");
}
BuiltinLintDiagnostics::ProcMacroBackCompat(note) => {
- db.note(&note);
+ db.note(note);
}
BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => {
db.span_suggestion(span, "use pat_param to preserve semantics", suggestion, Applicability::MachineApplicable);
@@ -747,13 +748,13 @@ pub trait LintContext: Sized {
} => {
db.span_note(
invoc_span,
- &format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
+ format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
);
}
BuiltinLintDiagnostics::TrailingMacro(is_trailing, name) => {
if is_trailing {
db.note("macro invocations at the end of a block are treated as expressions");
- db.note(&format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
+ db.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
}
}
BuiltinLintDiagnostics::BreakWithLabelAndLoop(span) => {
@@ -765,25 +766,55 @@ pub trait LintContext: Sized {
);
}
BuiltinLintDiagnostics::NamedAsmLabel(help) => {
- db.help(&help);
+ db.help(help);
db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
},
- BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), None) => {
- let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
- bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
- };
- let possibilities: Vec<Symbol> = names_valid.iter().map(|s| *s).collect();
+ BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => {
+ let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect();
// Suggest the most probable if we found one
if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
- db.span_suggestion(name_span, "did you mean", best_match, Applicability::MaybeIncorrect);
+ if let Some(ExpectedValues::Some(best_match_values)) =
+ sess.parse_sess.check_config.expecteds.get(&best_match) {
+ let mut possibilities = best_match_values.iter()
+ .flatten()
+ .map(Symbol::as_str)
+ .collect::<Vec<_>>();
+ possibilities.sort();
+
+ if let Some((value, value_span)) = value {
+ if best_match_values.contains(&Some(value)) {
+ db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect);
+ } else if best_match_values.contains(&None) {
+ db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect);
+ } else if let Some(first_value) = possibilities.first() {
+ db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect);
+ } else {
+ db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", best_match, Applicability::MaybeIncorrect);
+ };
+ } else {
+ db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+ }
+
+ if !possibilities.is_empty() {
+ let possibilities = possibilities.join("`, `");
+ db.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+ }
+ } else {
+ db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+ }
}
},
- BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
- let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
+ BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {
+ let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else {
bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
};
- let possibilities: Vec<Symbol> = values.iter().map(|&s| s).collect();
+ let mut have_none_possibility = false;
+ let possibilities: Vec<Symbol> = values.iter()
+ .inspect(|a| have_none_possibility |= a.is_none())
+ .copied()
+ .flatten()
+ .collect();
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
@@ -792,17 +823,24 @@ pub trait LintContext: Sized {
let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
possibilities.sort();
- let possibilities = possibilities.join(", ");
- db.note(&format!("expected values for `{name}` are: {possibilities}"));
+ let possibilities = possibilities.join("`, `");
+ let none = if have_none_possibility { "(none), " } else { "" };
+
+ db.note(format!("expected values for `{name}` are: {none}`{possibilities}`"));
}
- // Suggest the most probable if we found one
- if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
- db.span_suggestion(value_span, "did you mean", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+ if let Some((value, value_span)) = value {
+ // Suggest the most probable if we found one
+ if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
+ db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+
+ }
+ } else if let &[first_possibility] = &possibilities[..] {
+ db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect);
}
- } else {
- db.note(&format!("no expected value for `{name}`"));
- if name != sym::feature {
+ } else if have_none_possibility {
+ db.note(format!("no expected value for `{name}`"));
+ if let Some((_value, value_span)) = value {
db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect);
}
}
diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs
new file mode 100644
index 000000000..77e4a7669
--- /dev/null
+++ b/compiler/rustc_lint/src/drop_forget_useless.rs
@@ -0,0 +1,164 @@
+use rustc_hir::{Arm, Expr, ExprKind, Node};
+use rustc_span::sym;
+
+use crate::{
+ lints::{DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag},
+ LateContext, LateLintPass, LintContext,
+};
+
+declare_lint! {
+ /// The `dropping_references` lint checks for calls to `std::mem::drop` with a reference
+ /// instead of an owned value.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # fn operation_that_requires_mutex_to_be_unlocked() {} // just to make it compile
+ /// # let mutex = std::sync::Mutex::new(1); // just to make it compile
+ /// let mut lock_guard = mutex.lock();
+ /// std::mem::drop(&lock_guard); // Should have been drop(lock_guard), mutex
+ /// // still locked
+ /// operation_that_requires_mutex_to_be_unlocked();
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `drop` on a reference will only drop the
+ /// reference itself, which is a no-op. It will not call the `drop` method (from
+ /// the `Drop` trait implementation) on the underlying referenced value, which
+ /// is likely what was intended.
+ pub DROPPING_REFERENCES,
+ Warn,
+ "calls to `std::mem::drop` with a reference instead of an owned value"
+}
+
+declare_lint! {
+ /// The `forgetting_references` lint checks for calls to `std::mem::forget` with a reference
+ /// instead of an owned value.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = Box::new(1);
+ /// std::mem::forget(&x); // Should have been forget(x), x will still be dropped
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `forget` on a reference will only forget the
+ /// reference itself, which is a no-op. It will not forget the underlying
+ /// referenced value, which is likely what was intended.
+ pub FORGETTING_REFERENCES,
+ Warn,
+ "calls to `std::mem::forget` with a reference instead of an owned value"
+}
+
+declare_lint! {
+ /// The `dropping_copy_types` lint checks for calls to `std::mem::drop` with a value
+ /// that derives the Copy trait.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x: i32 = 42; // i32 implements Copy
+ /// std::mem::drop(x); // A copy of x is passed to the function, leaving the
+ /// // original unaffected
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `std::mem::drop` [does nothing for types that
+ /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
+ /// value will be copied and moved into the function on invocation.
+ pub DROPPING_COPY_TYPES,
+ Warn,
+ "calls to `std::mem::drop` with a value that implements Copy"
+}
+
+declare_lint! {
+ /// The `forgetting_copy_types` lint checks for calls to `std::mem::forget` with a value
+ /// that derives the Copy trait.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x: i32 = 42; // i32 implements Copy
+ /// std::mem::forget(x); // A copy of x is passed to the function, leaving the
+ /// // original unaffected
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `std::mem::forget` [does nothing for types that
+ /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
+ /// value will be copied and moved into the function on invocation.
+ ///
+ /// An alternative, but also valid, explanation is that Copy types do not
+ /// implement the Drop trait, which means they have no destructors. Without a
+ /// destructor, there is nothing for `std::mem::forget` to ignore.
+ pub FORGETTING_COPY_TYPES,
+ Warn,
+ "calls to `std::mem::forget` with a value that implements Copy"
+}
+
+declare_lint_pass!(DropForgetUseless => [DROPPING_REFERENCES, FORGETTING_REFERENCES, DROPPING_COPY_TYPES, FORGETTING_COPY_TYPES]);
+
+impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if let ExprKind::Call(path, [arg]) = expr.kind
+ && let ExprKind::Path(ref qpath) = path.kind
+ && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+ && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
+ {
+ let arg_ty = cx.typeck_results().expr_ty(arg);
+ let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
+ let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
+ match fn_name {
+ sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => {
+ cx.emit_spanned_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span });
+ },
+ sym::mem_forget if arg_ty.is_ref() => {
+ cx.emit_spanned_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span });
+ },
+ sym::mem_drop if is_copy && !drop_is_single_call_in_arm => {
+ cx.emit_spanned_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span });
+ }
+ sym::mem_forget if is_copy => {
+ cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span });
+ }
+ _ => return,
+ };
+ }
+ }
+}
+
+// Dropping returned value of a function, as in the following snippet is considered idiomatic, see
+// rust-lang/rust-clippy#9482 for examples.
+//
+// ```
+// match <var> {
+// <pat> => drop(fn_with_side_effect_and_returning_some_value()),
+// ..
+// }
+// ```
+fn is_single_call_in_arm<'tcx>(
+ cx: &LateContext<'tcx>,
+ arg: &'tcx Expr<'_>,
+ drop_expr: &'tcx Expr<'_>,
+) -> bool {
+ if arg.can_have_side_effects() {
+ let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id);
+ if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
+ return body.hir_id == drop_expr.hir_id;
+ }
+ }
+ false
+}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 65607d718..9f1f5a26e 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -428,7 +428,7 @@ pub fn check_ast_node_inner<'a, T: EarlyLintPass>(
for early_lint in lints {
sess.delay_span_bug(
early_lint.span,
- &format!(
+ format!(
"failed to process buffered lint here (dummy = {})",
id == ast::DUMMY_NODE_ID
),
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index f1ba192f2..2ce28f3a0 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -42,7 +42,7 @@ declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]);
/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
fn is_non_enum(t: Ty<'_>) -> bool {
- !t.is_enum() && !t.needs_subst()
+ !t.is_enum() && !t.has_param()
}
fn enforce_mem_discriminant(
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 9af5284df..bbae3d368 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -81,7 +81,7 @@ pub struct UnknownToolInScopedLint {
#[derive(Diagnostic)]
#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
-pub struct BuiltinEllpisisInclusiveRangePatterns {
+pub struct BuiltinEllipsisInclusiveRangePatterns {
#[primary_span]
pub span: Span,
#[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index e9eb14ea1..b1266b58a 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -1,5 +1,5 @@
use crate::lints::{Expectation, ExpectationNote};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
use rustc_session::lint::LintExpectationId;
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 4ac589c2e..6f773e04a 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -4,6 +4,7 @@
use crate::lints::{
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
+ UntranslatableDiagnosticTrivial,
};
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
@@ -366,7 +367,15 @@ declare_tool_lint! {
report_in_external_macro: true
}
-declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL ]);
+declare_tool_lint! {
+ /// The `untranslatable_diagnostic_trivial` lint detects diagnostics created using only static strings.
+ pub rustc::UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL,
+ Deny,
+ "prevent creation of diagnostics which cannot be translated, which use only static strings",
+ report_in_external_macro: true
+}
+
+declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL, UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL ]);
impl LateLintPass<'_> for Diagnostics {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -374,9 +383,8 @@ impl LateLintPass<'_> for Diagnostics {
debug!(?span, ?def_id, ?substs);
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs)
.ok()
- .and_then(|inst| inst)
- .map(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics))
- .unwrap_or(false);
+ .flatten()
+ .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
if !has_attr {
return;
}
@@ -423,6 +431,77 @@ impl LateLintPass<'_> for Diagnostics {
}
}
+impl EarlyLintPass for Diagnostics {
+ #[allow(unused_must_use)]
+ fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
+ // Looking for a straight chain of method calls from 'struct_span_err' to 'emit'.
+ let ast::StmtKind::Semi(expr) = &stmt.kind else {
+ return;
+ };
+ let ast::ExprKind::MethodCall(meth) = &expr.kind else {
+ return;
+ };
+ if meth.seg.ident.name != sym::emit || !meth.args.is_empty() {
+ return;
+ }
+ let mut segments = vec![];
+ let mut cur = &meth.receiver;
+ let fake = &[].into();
+ loop {
+ match &cur.kind {
+ ast::ExprKind::Call(func, args) => {
+ if let ast::ExprKind::Path(_, path) = &func.kind {
+ segments.push((path.segments.last().unwrap().ident.name, args))
+ }
+ break;
+ }
+ ast::ExprKind::MethodCall(method) => {
+ segments.push((method.seg.ident.name, &method.args));
+ cur = &method.receiver;
+ }
+ ast::ExprKind::MacCall(mac) => {
+ segments.push((mac.path.segments.last().unwrap().ident.name, fake));
+ break;
+ }
+ _ => {
+ break;
+ }
+ }
+ }
+ segments.reverse();
+ if segments.is_empty() {
+ return;
+ }
+ if segments[0].0.as_str() != "struct_span_err" {
+ return;
+ }
+ if !segments.iter().all(|(name, args)| {
+ let arg = match name.as_str() {
+ "struct_span_err" | "span_note" | "span_label" | "span_help" if args.len() == 2 => {
+ &args[1]
+ }
+ "note" | "help" if args.len() == 1 => &args[0],
+ _ => {
+ return false;
+ }
+ };
+ if let ast::ExprKind::Lit(lit) = arg.kind
+ && let ast::token::LitKind::Str = lit.kind {
+ true
+ } else {
+ false
+ }
+ }) {
+ return;
+ }
+ cx.emit_spanned_lint(
+ UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL,
+ stmt.span,
+ UntranslatableDiagnosticTrivial,
+ );
+ }
+}
+
declare_tool_lint! {
/// The `bad_opt_access` lint detects accessing options by field instead of
/// the wrapper function.
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index b42878a02..8a4a451f8 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -16,7 +16,7 @@
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
use rustc_ast as ast;
-use rustc_data_structures::sync::join;
+use rustc_data_structures::sync::{join, DynSend};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit as hir_visit;
@@ -240,8 +240,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
}
fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
- lint_callback!(self, check_arm, a);
- hir_visit::walk_arm(self, a);
+ self.with_lint_attrs(a.hir_id, |cx| {
+ lint_callback!(cx, check_arm, a);
+ hir_visit::walk_arm(cx, a);
+ })
}
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
@@ -429,7 +431,7 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
/// Performs lint checking on a crate.
pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(
tcx: TyCtxt<'tcx>,
- builtin_lints: impl FnOnce() -> T + Send,
+ builtin_lints: impl FnOnce() -> T + Send + DynSend,
) {
join(
|| {
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index bb863f095..8376835f5 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -14,13 +14,13 @@ use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirId;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::{
reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource,
ShallowLintLevelMap,
};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
use rustc_session::lint::{
@@ -242,7 +242,9 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> {
struct QueryMapExpectationsWrapper<'tcx> {
tcx: TyCtxt<'tcx>,
+ /// HirId of the currently investigated element.
cur: HirId,
+ /// Level map for `cur`.
specs: ShallowLintLevelMap,
expectations: Vec<(LintExpectationId, LintExpectation)>,
unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>,
@@ -255,11 +257,11 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> {
self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
}
fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
- let specs = self.specs.specs.get_mut_or_insert_default(self.cur.local_id);
- specs.clear();
- specs.insert(id, lvl);
+ self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl);
}
fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
+ // We cannot use `tcx.lint_level_at_node` because we want to know in which order the
+ // attributes have been inserted, in particular whether an `expect` follows a `forbid`.
self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
}
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
@@ -355,7 +357,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
fn add_id(&mut self, hir_id: HirId) {
+ // Change both the `HirId` and the associated specs.
self.provider.cur = hir_id;
+ self.provider.specs.specs.clear();
self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id));
}
}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b35785405..dfddfe09a 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -52,6 +52,7 @@ mod array_into_iter;
pub mod builtin;
mod context;
mod deref_into_dyn_supertrait;
+mod drop_forget_useless;
mod early;
mod enum_intrinsics_non_enums;
mod errors;
@@ -82,10 +83,10 @@ pub use array_into_iter::ARRAY_INTO_ITER;
use rustc_ast as ast;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_macros::fluent_messages;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::{
BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
@@ -96,6 +97,7 @@ use rustc_span::Span;
use array_into_iter::ArrayIntoIter;
use builtin::*;
use deref_into_dyn_supertrait::*;
+use drop_forget_useless::*;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
use for_loops_over_fallibles::*;
use hidden_unicode_codepoints::*;
@@ -201,6 +203,7 @@ late_lint_methods!(
[
ForLoopsOverFallibles: ForLoopsOverFallibles,
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
+ DropForgetUseless: DropForgetUseless,
HardwiredLints: HardwiredLints,
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
@@ -518,6 +521,7 @@ fn register_internals(store: &mut LintStore) {
store.register_lints(&TyTyKind::get_lints());
store.register_late_pass(|_| Box::new(TyTyKind));
store.register_lints(&Diagnostics::get_lints());
+ store.register_early_pass(|| Box::new(Diagnostics));
store.register_late_pass(|_| Box::new(Diagnostics));
store.register_lints(&BadOptAccess::get_lints());
store.register_late_pass(|_| Box::new(BadOptAccess));
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 1d5e02369..d96723a68 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -662,6 +662,43 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> {
pub end_span: Span,
}
+// drop_forget_useless.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_dropping_references)]
+#[note]
+pub struct DropRefDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_dropping_copy_types)]
+#[note]
+pub struct DropCopyDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_forgetting_references)]
+#[note]
+pub struct ForgetRefDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_forgetting_copy_types)]
+#[note]
+pub struct ForgetCopyDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
// hidden_unicode_codepoints.rs
#[derive(LintDiagnostic)]
#[diag(lint_hidden_unicode_codepoints)]
@@ -821,6 +858,10 @@ pub struct DiagOutOfImpl;
pub struct UntranslatableDiag;
#[derive(LintDiagnostic)]
+#[diag(lint_trivial_untranslatable_diag)]
+pub struct UntranslatableDiagnosticTrivial;
+
+#[derive(LintDiagnostic)]
#[diag(lint_bad_opt_access)]
pub struct BadOptAccessDiag<'a> {
pub msg: &'a str,
@@ -1146,6 +1187,18 @@ pub struct NoopMethodCallDiag<'a> {
pub label: Span,
}
+#[derive(LintDiagnostic)]
+#[diag(lint_suspicious_double_ref_deref)]
+pub struct SuspiciousDoubleRefDerefDiag<'a> {
+ pub ty: Ty<'a>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_suspicious_double_ref_clone)]
+pub struct SuspiciousDoubleRefCloneDiag<'a> {
+ pub ty: Ty<'a>,
+}
+
// pass_by_value.rs
#[derive(LintDiagnostic)]
#[diag(lint_pass_by_value)]
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 5bb1abfd2..b218cc578 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -128,7 +128,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
// No clue where this argument is coming from.
return lint;
}
- if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
+ if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`.
lint.note(fluent::lint_supports_fmt_note);
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 9efc14849..79253cbc8 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -33,6 +33,11 @@ pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext
}
}
+fn assoc_item_in_trait_impl(cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) -> bool {
+ let item = cx.tcx.associated_item(ii.owner_id);
+ item.trait_item_def_id.is_some()
+}
+
declare_lint! {
/// The `non_camel_case_types` lint detects types, variants, traits and
/// type parameters that don't have camel case names.
@@ -177,6 +182,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
// trait impls where we should have warned for the trait definition already.
ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => {
for it in items {
+ // FIXME: this doesn't respect `#[allow(..)]` on the item itself.
if let ast::AssocItemKind::Type(..) = it.kind {
self.check_case(cx, "associated type", &it.ident);
}
@@ -505,7 +511,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) {
- if let hir::ImplItemKind::Const(..) = ii.kind {
+ if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident);
}
}
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index d67a00619..d56c35bb6 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,10 +1,13 @@
use crate::context::LintContext;
-use crate::lints::NoopMethodCallDiag;
+use crate::lints::{
+ NoopMethodCallDiag, SuspiciousDoubleRefCloneDiag, SuspiciousDoubleRefDerefDiag,
+};
use crate::LateContext;
use crate::LateLintPass;
use rustc_hir::def::DefKind;
use rustc_hir::{Expr, ExprKind};
use rustc_middle::ty;
+use rustc_middle::ty::adjustment::Adjust;
use rustc_span::symbol::sym;
declare_lint! {
@@ -35,32 +38,62 @@ declare_lint! {
"detects the use of well-known noop methods"
}
-declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
+declare_lint! {
+ /// The `suspicious_double_ref_op` lint checks for usage of `.clone()`/`.borrow()`/`.deref()`
+ /// on an `&&T` when `T: !Deref/Borrow/Clone`, which means the call will return the inner `&T`,
+ /// instead of performing the operation on the underlying `T` and can be confusing.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// struct Foo;
+ /// let foo = &&Foo;
+ /// let clone: &Foo = foo.clone();
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Since `Foo` doesn't implement `Clone`, running `.clone()` only dereferences the double
+ /// reference, instead of cloning the inner type which should be what was intended.
+ pub SUSPICIOUS_DOUBLE_REF_OP,
+ Warn,
+ "suspicious call of trait method on `&&T`"
+}
+
+declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL, SUSPICIOUS_DOUBLE_REF_OP]);
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls.
- let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
- return
+ let ExprKind::MethodCall(call, receiver, _, call_span) = &expr.kind else {
+ return;
};
+
+ if call_span.from_expansion() {
+ return;
+ }
+
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
// traits and ignore any other method call.
- let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
- // Verify we are dealing with a method/associated function.
- Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
- // Check that we're dealing with a trait method for one of the traits we care about.
- Some(trait_id)
- if matches!(
- cx.tcx.get_diagnostic_name(trait_id),
- Some(sym::Borrow | sym::Clone | sym::Deref)
- ) =>
- {
- did
- }
- _ => return,
- },
- _ => return,
+
+ let Some((DefKind::AssocFn, did)) =
+ cx.typeck_results().type_dependent_def(expr.hir_id)
+ else {
+ return;
};
+
+ let Some(trait_id) = cx.tcx.trait_of_item(did) else { return };
+
+ if !matches!(
+ cx.tcx.get_diagnostic_name(trait_id),
+ Some(sym::Borrow | sym::Clone | sym::Deref)
+ ) {
+ return;
+ };
+
let substs = cx
.tcx
.normalize_erasing_regions(cx.param_env, cx.typeck_results().node_substs(expr.hir_id));
@@ -70,25 +103,43 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
};
// (Re)check that it implements the noop diagnostic.
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
- if !matches!(
- name,
- sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
- ) {
- return;
- }
+
let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
- if receiver_ty != expr_ty {
- // This lint will only trigger if the receiver type and resulting expression \
- // type are the same, implying that the method call is unnecessary.
+ let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
+
+ // If there is any user defined auto-deref step, then we don't want to warn.
+ // https://github.com/rust-lang/rust-clippy/issues/9272
+ if arg_adjustments.iter().any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) {
return;
}
+
let expr_span = expr.span;
let span = expr_span.with_lo(receiver.span.hi());
- cx.emit_spanned_lint(
- NOOP_METHOD_CALL,
- span,
- NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
- );
+
+ if receiver_ty == expr_ty {
+ cx.emit_spanned_lint(
+ NOOP_METHOD_CALL,
+ span,
+ NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
+ );
+ } else {
+ match name {
+ // If `type_of(x) == T` and `x.borrow()` is used to get `&T`,
+ // then that should be allowed
+ sym::noop_method_borrow => return,
+ sym::noop_method_clone => cx.emit_spanned_lint(
+ SUSPICIOUS_DOUBLE_REF_OP,
+ span,
+ SuspiciousDoubleRefCloneDiag { ty: expr_ty },
+ ),
+ sym::noop_method_deref => cx.emit_spanned_lint(
+ SUSPICIOUS_DOUBLE_REF_OP,
+ span,
+ SuspiciousDoubleRefDerefDiag { ty: expr_ty },
+ ),
+ _ => return,
+ }
+ }
}
}
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index f9d43fe22..15715c8fc 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
// For every projection predicate in the opaque type's explicit bounds,
// check that the type that we're assigning actually satisfies the bounds
// of the associated type.
- for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) {
+ for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
// Liberate bound regions in the predicate since we
// don't actually care about lifetimes in this check.
let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind());
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
// with `impl Send: OtherTrait`.
for (assoc_pred, assoc_pred_span) in cx
.tcx
- .bound_explicit_item_bounds(proj.projection_ty.def_id)
+ .explicit_item_bounds(proj.projection_ty.def_id)
.subst_iter_copied(cx.tcx, &proj.projection_ty.substs)
{
let assoc_pred = assoc_pred.fold_with(proj_replacer);
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index a6ba74220..4bf4fda82 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -677,7 +677,7 @@ pub fn transparent_newtype_field<'a, 'tcx>(
let param_env = tcx.param_env(variant.def_id);
variant.fields.iter().find(|field| {
let field_ty = tcx.type_of(field.did).subst_identity();
- let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst());
+ let is_zst = tcx.layout_of(param_env.and(field_ty)).is_ok_and(|layout| layout.is_zst());
!is_zst
})
}
@@ -1119,14 +1119,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
// so they are currently ignored for the purposes of this lint.
- ty::Param(..) | ty::Alias(ty::Projection, ..)
+ ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
if matches!(self.mode, CItemKind::Definition) =>
{
FfiSafe
}
ty::Param(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Infer(..)
| ty::Bound(..)
| ty::Error(_)
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 28cc63198..8f75fa11d 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
- elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned())
+ elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).subst_identity_iter_copied())
// We only care about self bounds for the impl-trait
.filter_only_self()
.find_map(|(pred, _span)| {
@@ -571,36 +571,50 @@ trait UnusedDelimLint {
}
}
- // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
- let lhs_needs_parens = {
+ // Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`.
+ {
let mut innermost = inner;
loop {
innermost = match &innermost.kind {
- ExprKind::Binary(_, lhs, _rhs) => lhs,
+ ExprKind::Binary(_op, lhs, _rhs) => lhs,
ExprKind::Call(fn_, _params) => fn_,
ExprKind::Cast(expr, _ty) => expr,
ExprKind::Type(expr, _ty) => expr,
ExprKind::Index(base, _subscript) => base,
- _ => break false,
+ _ => break,
};
if !classify::expr_requires_semi_to_be_stmt(innermost) {
- break true;
+ return true;
}
}
- };
+ }
- lhs_needs_parens
- || (followed_by_block
- && match &inner.kind {
- ExprKind::Ret(_)
- | ExprKind::Break(..)
- | ExprKind::Yield(..)
- | ExprKind::Yeet(..) => true,
- ExprKind::Range(_lhs, Some(rhs), _limits) => {
- matches!(rhs.kind, ExprKind::Block(..))
- }
- _ => parser::contains_exterior_struct_lit(&inner),
- })
+ // Check if RHS needs parens to prevent false-positives in cases like `if (() == return) {}`.
+ if !followed_by_block {
+ return false;
+ }
+ let mut innermost = inner;
+ loop {
+ innermost = match &innermost.kind {
+ ExprKind::Unary(_op, expr) => expr,
+ ExprKind::Binary(_op, _lhs, rhs) => rhs,
+ ExprKind::AssignOp(_op, _lhs, rhs) => rhs,
+ ExprKind::Assign(_lhs, rhs, _span) => rhs,
+
+ ExprKind::Ret(_) | ExprKind::Yield(..) | ExprKind::Yeet(..) => return true,
+
+ ExprKind::Break(_label, None) => return false,
+ ExprKind::Break(_label, Some(break_expr)) => {
+ return matches!(break_expr.kind, ExprKind::Block(..));
+ }
+
+ ExprKind::Range(_lhs, Some(rhs), _limits) => {
+ return matches!(rhs.kind, ExprKind::Block(..));
+ }
+
+ _ => return parser::contains_exterior_struct_lit(&inner),
+ }
+ }
}
fn emit_unused_delims_expr(
@@ -638,26 +652,20 @@ trait UnusedDelimLint {
return;
}
let spans = match value.kind {
- ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => {
- if let Some(span) = block.stmts[0].span.find_ancestor_inside(value.span) {
- Some((value.span.with_hi(span.lo()), value.span.with_lo(span.hi())))
- } else {
- None
- }
- }
+ ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0]
+ .span
+ .find_ancestor_inside(value.span)
+ .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
ast::ExprKind::Paren(ref expr) => {
- let expr_span = expr.span.find_ancestor_inside(value.span);
- if let Some(expr_span) = expr_span {
- Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
- } else {
- None
- }
+ expr.span.find_ancestor_inside(value.span).map(|expr_span| {
+ (value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi()))
+ })
}
_ => return,
};
let keep_space = (
- left_pos.map_or(false, |s| s >= value.span.lo()),
- right_pos.map_or(false, |s| s <= value.span.hi()),
+ left_pos.is_some_and(|s| s >= value.span.lo()),
+ right_pos.is_some_and(|s| s <= value.span.hi()),
);
self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
}
@@ -930,11 +938,10 @@ impl UnusedParens {
// Otherwise proceed with linting.
_ => {}
}
- let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
- Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
- } else {
- None
- };
+ let spans = inner
+ .span
+ .find_ancestor_inside(value.span)
+ .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())));
self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space);
}
}
@@ -1045,11 +1052,11 @@ impl EarlyLintPass for UnusedParens {
if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
_ => {
- let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
- Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
- } else {
- None
- };
+ let spans = r
+ .span
+ .find_ancestor_inside(ty.span)
+ .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())));
+
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
}
}