diff options
Diffstat (limited to 'compiler/rustc_lint')
22 files changed, 1075 insertions, 220 deletions
diff --git a/compiler/rustc_lint/locales/en-US.ftl b/compiler/rustc_lint/locales/en-US.ftl new file mode 100644 index 000000000..68e62c978 --- /dev/null +++ b/compiler/rustc_lint/locales/en-US.ftl @@ -0,0 +1,510 @@ +lint_array_into_iter = + this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021 + .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity + .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value + .use_explicit_into_iter_suggestion = + or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + +lint_enum_intrinsics_mem_discriminant = + the return value of `mem::discriminant` is unspecified when called with a non-enum type + .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. + +lint_enum_intrinsics_mem_variant = + the return value of `mem::variant_count` is unspecified when called with a non-enum type + .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. + +lint_expectation = this lint expectation is unfulfilled + .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + .rationale = {$rationale} + +lint_for_loops_over_fallibles = + for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement + .suggestion = consider using `if let` to clear intent + .remove_next = to iterate over `{$recv_snip}` remove the call to `next` + .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_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} + .label = this {$label} contains {$count -> + [one] an invisible + *[other] invisible + } unicode text flow control {$count -> + [one] codepoint + *[other] codepoints + } + .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + .suggestion_remove = if their presence wasn't intentional, you can remove them + .suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them + .no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} + +lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance + .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary + +lint_query_instability = using `{$query}` can result in unstable query results + .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +lint_tykind_kind = usage of `ty::TyKind::<kind>` + .suggestion = try using `ty::<kind>` directly + +lint_tykind = usage of `ty::TyKind` + .help = try using `Ty` instead + +lint_ty_qualified = usage of qualified `ty::{$ty}` + .suggestion = try importing it and using it unqualified + +lint_lintpass_by_hand = implementing `LintPass` by hand + .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead + +lint_non_existant_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]` + .help = only existing keywords are allowed in core/std + +lint_diag_out_of_impl = + diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls + +lint_untranslatable_diag = diagnostics should be created using translatable messages + +lint_bad_opt_access = {$msg} + +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_multple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits + +lint_identifier_non_ascii_char = identifier contains non-ASCII characters + +lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints + +lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` + .label = this is where the previous identifier occurred + +lint_mixed_script_confusables = + the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables + .includes_note = the usage includes {$includes} + .note = please recheck to make sure their usages are indeed what you want + +lint_non_fmt_panic = panic message is not a string literal + .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021 + .more_info_note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html> + .supports_fmt_note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here + .supports_fmt_suggestion = remove the `format!(..)` macro call + .display_suggestion = add a "{"{"}{"}"}" format string to `Display` the message + .debug_suggestion = + add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}` + .panic_suggestion = {$already_suggested -> + [true] or use + *[false] use + } std::panic::panic_any instead + +lint_non_fmt_panic_unused = + panic message contains {$count -> + [one] an unused + *[other] unused + } formatting {$count -> + [one] placeholder + *[other] placeholders + } + .note = this message is not used as a format string when given without arguments, but will be in Rust 2021 + .add_args_suggestion = add the missing {$count -> + [one] argument + *[other] arguments + } + .add_fmt_suggestion = or add a "{"{"}{"}"}" format string to use the message literally + +lint_non_fmt_panic_braces = + panic message contains {$count -> + [one] a brace + *[other] braces + } + .note = this message is not used as a format string, but will be in Rust 2021 + .suggestion = add a "{"{"}{"}"}" format string to use the message literally + +lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name + .suggestion = convert the identifier to upper camel case + .label = should have an UpperCamelCase name + +lint_non_snake_case = {$sort} `{$name}` should have a snake case name + .rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier + .cannot_convert_note = `{$sc}` cannot be used as a raw identifier + .rename_suggestion = rename the identifier + .convert_suggestion = convert the identifier to snake case + .help = convert the identifier to snake case: `{$sc}` + .label = should have a snake_case name + +lint_non_upper_case_global = {$sort} `{$name}` should have an upper case name + .suggestion = convert the identifier to upper case + .label = should have an UPPER_CASE name + +lint_noop_method_call = call to `.{$method}()` on a reference in this situation does nothing + .label = unnecessary method call + .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed + +lint_pass_by_value = passing `{$ty}` by reference + .suggestion = try passing by value + +lint_redundant_semicolons = + unnecessary trailing {$multiple -> + [true] semicolons + *[false] semicolon + } + .suggestion = remove {$multiple -> + [true] these semicolons + *[false] this semicolon + } + +lint_drop_trait_constraints = + bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped + +lint_drop_glue = + types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped + +lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}` + .suggestion = use an inclusive range instead + +lint_overflowing_bin_hex = literal out of range for `{$ty}` + .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` + .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` + .positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` + .suggestion = consider using the type `{$suggestion_ty}` instead + .help = consider using the type `{$suggestion_ty}` instead + +lint_overflowing_int = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + .help = consider using the type `{$suggestion_ty}` instead + +lint_only_cast_u8_to_char = only `u8` can be cast into `char` + .suggestion = use a `char` literal instead + +lint_overflowing_uint = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + +lint_overflowing_literal = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY` + +lint_unused_comparisons = comparison is useless due to type limits + +lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe + .label = not FFI-safe + .note = the type is defined here + +lint_improper_ctypes_opaque = opaque types have no C equivalent + +lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention +lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead + +lint_improper_ctypes_tuple_reason = tuples have unspecified layout +lint_improper_ctypes_tuple_help = consider using a struct instead + +lint_improper_ctypes_str_reason = string slices have no C equivalent +lint_improper_ctypes_str_help = consider using `*const u8` and a length instead + +lint_improper_ctypes_dyn = trait objects have no C equivalent + +lint_improper_ctypes_slice_reason = slices have no C equivalent +lint_improper_ctypes_slice_help = consider using a raw pointer instead + +lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI + +lint_improper_ctypes_char_reason = the `char` type has no C equivalent +lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead + +lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive +lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants + +lint_improper_ctypes_enum_repr_reason = enum has no representation hint +lint_improper_ctypes_enum_repr_help = + consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + +lint_improper_ctypes_struct_fieldless_reason = this struct has no fields +lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct + +lint_improper_ctypes_union_fieldless_reason = this union has no fields +lint_improper_ctypes_union_fieldless_help = consider adding a member to this union + +lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive +lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive + +lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout +lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + +lint_improper_ctypes_union_layout_reason = this union has unspecified layout +lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union + +lint_improper_ctypes_box = box cannot be represented as a single pointer + +lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field + +lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields + +lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe +lint_improper_ctypes_array_help = consider passing a pointer to the array + +lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` + +lint_variant_size_differences = + enum variant is more than three times larger ({$largest} bytes) than the next largest + +lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering + .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering + .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering + .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` + +lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write + .label = invalid failure ordering + .help = consider using `Acquire` or `Relaxed` failure ordering instead + +lint_unused_op = unused {$op} that must be used + .label = the {$op} produces a value + .suggestion = use `let _ = ...` to ignore the resulting value + +lint_unused_result = unused result of type `{$ty}` + +lint_unused_closure = + unused {$pre}{$count -> + [one] closure + *[other] closures + }{$post} that must be used + .note = closures are lazy and do nothing unless called + +lint_unused_generator = + unused {$pre}{$count -> + [one] generator + *[other] generator + }{$post} that must be used + .note = generators are lazy and do nothing unless resumed + +lint_unused_def = unused {$pre}`{$def}`{$post} that must be used + .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_check_name_warning = {$msg} + +lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name} + +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 diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 3593f141d..bccb0a94e 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -1,5 +1,7 @@ -use crate::lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub}; -use crate::{LateContext, LateLintPass, LintContext}; +use crate::{ + lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub}, + LateContext, LateLintPass, LintContext, +}; use rustc_hir as hir; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index fe188162c..5b2100b5d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -20,6 +20,7 @@ //! If you define a new `LateLintPass`, you will also need to add it to the //! `late_lint_methods!` invocation in `lib.rs`. +use crate::fluent_generated as fluent; use crate::{ errors::BuiltinEllpisisInclusiveRangePatterns, lints::{ @@ -50,15 +51,13 @@ use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{fluent, Applicability, DecorateLint, MultiSpan}; +use rustc_errors::{Applicability, DecorateLint, MultiSpan}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{ - Body, FnDecl, ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin, -}; +use rustc_hir::{Body, FnDecl, ForeignItemKind, GenericParamKind, Node, PatKind, PredicateOrigin}; use rustc_index::vec::Idx; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; @@ -185,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers { | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { - self.check_heap_type(cx, it.span, cx.tcx.type_of(it.owner_id)) + self.check_heap_type(cx, it.span, cx.tcx.type_of(it.owner_id).subst_identity()) } _ => (), } @@ -194,7 +193,11 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers { match it.kind { hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { for field in struct_def.fields() { - self.check_heap_type(cx, field.span, cx.tcx.type_of(field.def_id)); + self.check_heap_type( + cx, + field.span, + cx.tcx.type_of(field.def_id).subst_identity(), + ); } } _ => (), @@ -582,26 +585,28 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { - // If the method is an impl for a trait, don't doc. - if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl { - return; - } - - // If the method is an impl for an item with docs_hidden, don't doc. - if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl { - let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); - let impl_ty = cx.tcx.type_of(parent); - let outerdef = match impl_ty.kind() { - ty::Adt(def, _) => Some(def.did()), - ty::Foreign(def_id) => Some(*def_id), - _ => None, - }; - let is_hidden = match outerdef { - Some(id) => cx.tcx.is_doc_hidden(id), - None => false, - }; - if is_hidden { - return; + let context = method_context(cx, impl_item.owner_id.def_id); + + match context { + // If the method is an impl for a trait, don't doc. + MethodLateContext::TraitImpl => return, + MethodLateContext::TraitAutoImpl => {} + // If the method is an impl for an item with docs_hidden, don't doc. + MethodLateContext::PlainImpl => { + let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()); + let impl_ty = cx.tcx.type_of(parent).subst_identity(); + let outerdef = match impl_ty.kind() { + ty::Adt(def, _) => Some(def.did()), + ty::Foreign(def_id) => Some(*def_id), + _ => None, + }; + let is_hidden = match outerdef { + Some(id) => cx.tcx.is_doc_hidden(id), + None => false, + }; + if is_hidden { + return; + } } } @@ -672,21 +677,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { return; } let def = cx.tcx.adt_def(item.owner_id); - (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) + (def, cx.tcx.mk_adt(def, ty::List::empty())) } hir::ItemKind::Union(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } let def = cx.tcx.adt_def(item.owner_id); - (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) + (def, cx.tcx.mk_adt(def, ty::List::empty())) } hir::ItemKind::Enum(_, ref ast_generics) => { if !ast_generics.params.is_empty() { return; } let def = cx.tcx.adt_def(item.owner_id); - (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) + (def, cx.tcx.mk_adt(def, ty::List::empty())) } _ => return, }; @@ -698,7 +703,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { // and recommending Copy might be a bad idea. for field in def.all_fields() { let did = field.did; - if cx.tcx.type_of(did).is_unsafe_ptr() { + if cx.tcx.type_of(did).subst_identity().is_unsafe_ptr() { return; } } @@ -732,7 +737,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { cx.tcx, param_env, ty, - traits::ObligationCause::misc(item.span, item.hir_id()), + traits::ObligationCause::misc(item.span, item.owner_id.def_id), ) .is_ok() { @@ -798,7 +803,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { if self.impling_types.is_none() { let mut impls = LocalDefIdSet::default(); cx.tcx.for_each_impl(debug, |d| { - if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() { + if let Some(ty_def) = cx.tcx.type_of(d).subst_identity().ty_adt_def() { if let Some(def_id) = ty_def.did().as_local() { impls.insert(def_id); } @@ -1283,7 +1288,7 @@ declare_lint! { } declare_lint_pass!( - /// Explains corresponding feature flag must be enabled for the `#[track_caller] attribute to + /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to /// do anything UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER] ); @@ -1296,19 +1301,18 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { _: &'tcx FnDecl<'_>, _: &'tcx Body<'_>, span: Span, - hir_id: HirId, + def_id: LocalDefId, ) { if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller - && let attrs = cx.tcx.hir().attrs(hir_id) // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller)) - { - cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { - label: span, - parse_sess: &cx.tcx.sess.parse_sess, - }); - } + && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller) + { + cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { + label: span, + parse_sess: &cx.tcx.sess.parse_sess, + }); + } } } @@ -1580,7 +1584,7 @@ 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::TypeVisitable; + use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::Clause; use rustc_middle::ty::PredicateKind::*; @@ -1592,15 +1596,19 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { Clause(Clause::TypeOutlives(..)) | Clause(Clause::RegionOutlives(..)) => "lifetime", + // `ConstArgHasType` is never global as `ct` is always a param + Clause(Clause::ConstArgHasType(..)) | // Ignore projections, as they can only be global // if the trait bound is global Clause(Clause::Projection(..)) | + AliasEq(..) | // Ignore bounds that a user can't type WellFormed(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | Coerce(..) | + // FIXME(generic_const_exprs): `ConstEvaluatable` can be written ConstEvaluatable(..) | ConstEquate(..) | Ambiguous | @@ -2006,7 +2014,7 @@ impl ExplicitOutlivesRequirements { inferred_outlives: &[ty::Region<'tcx>], predicate_span: Span, ) -> Vec<(usize, Span)> { - use rustc_middle::middle::resolve_lifetime::Region; + use rustc_middle::middle::resolve_bound_vars::ResolvedArg; bounds .iter() @@ -2016,8 +2024,8 @@ impl ExplicitOutlivesRequirements { return None; }; - let is_inferred = match tcx.named_region(lifetime.hir_id) { - Some(Region::EarlyBound(def_id)) => inferred_outlives + let is_inferred = match tcx.named_bound_var(lifetime.hir_id) { + Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives .iter() .any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })), _ => false, @@ -2096,7 +2104,7 @@ impl ExplicitOutlivesRequirements { impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - use rustc_middle::middle::resolve_lifetime::Region; + use rustc_middle::middle::resolve_bound_vars::ResolvedArg; let def_id = item.owner_id.def_id; if let hir::ItemKind::Struct(_, hir_generics) @@ -2119,8 +2127,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { let (relevant_lifetimes, bounds, predicate_span, in_where_clause) = match where_predicate { hir::WherePredicate::RegionPredicate(predicate) => { - if let Some(Region::EarlyBound(region_def_id)) = - cx.tcx.named_region(predicate.lifetime.hir_id) + if let Some(ResolvedArg::EarlyBound(region_def_id)) = + cx.tcx.named_bound_var(predicate.lifetime.hir_id) { ( Self::lifetimes_outliving_lifetime( @@ -2175,13 +2183,31 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { dropped_predicate_count += 1; } - if drop_predicate && !in_where_clause { - lint_spans.push(predicate_span); - } else if drop_predicate && i + 1 < num_predicates { - // If all the bounds on a predicate were inferable and there are - // further predicates, we want to eat the trailing comma. - let next_predicate_span = hir_generics.predicates[i + 1].span(); - where_lint_spans.push(predicate_span.to(next_predicate_span.shrink_to_lo())); + if drop_predicate { + if !in_where_clause { + lint_spans.push(predicate_span); + } else if predicate_span.from_expansion() { + // Don't try to extend the span if it comes from a macro expansion. + where_lint_spans.push(predicate_span); + } else if i + 1 < num_predicates { + // If all the bounds on a predicate were inferable and there are + // further predicates, we want to eat the trailing comma. + let next_predicate_span = hir_generics.predicates[i + 1].span(); + if next_predicate_span.from_expansion() { + where_lint_spans.push(predicate_span); + } else { + where_lint_spans + .push(predicate_span.to(next_predicate_span.shrink_to_lo())); + } + } else { + // Eat the optional trailing comma after the last predicate. + let where_span = hir_generics.where_clause_span; + if where_span.from_expansion() { + where_lint_spans.push(predicate_span); + } else { + where_lint_spans.push(predicate_span.to(where_span.shrink_to_hi())); + } + } } else { where_lint_spans.extend(self.consolidate_outlives_bound_spans( predicate_span.shrink_to_lo(), @@ -2225,6 +2251,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { Applicability::MaybeIncorrect }; + // Due to macros, there might be several predicates with the same span + // and we only want to suggest removing them once. + lint_spans.sort_unstable(); + lint_spans.dedup(); + cx.emit_spanned_lint( EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), @@ -2284,11 +2315,8 @@ impl EarlyLintPass for IncompleteFeatures { .for_each(|(&name, &span)| { let note = rustc_feature::find_feature_issue(name, GateIssue::Language) .map(|n| BuiltinIncompleteFeaturesNote { n }); - let help = if HAS_MIN_FEATURES.contains(&name) { - Some(BuiltinIncompleteFeaturesHelp) - } else { - None - }; + let help = + HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp); cx.emit_spanned_lint( INCOMPLETE_FEATURES, span, @@ -2581,7 +2609,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init)) } Array(ty, len) => { - if matches!(len.try_eval_usize(cx.tcx, cx.param_env), Some(v) if v > 0) { + if matches!(len.try_eval_target_usize(cx.tcx, cx.param_env), Some(v) if v > 0) { // Array length known at array non-empty -- recurse. ty_find_init_error(cx, *ty, init) } else { @@ -2608,7 +2636,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { cx.emit_spanned_lint( INVALID_VALUE, expr.span, - BuiltinUnpermittedTypeInit { msg, ty: conjured_ty, label: expr.span, sub }, + BuiltinUnpermittedTypeInit { + msg, + ty: conjured_ty, + label: expr.span, + sub, + tcx: cx.tcx, + }, ); } } @@ -2661,7 +2695,7 @@ pub struct ClashingExternDeclarations { /// the symbol should be reported as a clashing declaration. // FIXME: Technically, we could just store a &'tcx str here without issue; however, the // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime. - seen_decls: FxHashMap<Symbol, HirId>, + seen_decls: FxHashMap<Symbol, hir::OwnerId>, } /// Differentiate between whether the name for an extern decl came from the link_name attribute or @@ -2687,19 +2721,20 @@ impl ClashingExternDeclarations { pub(crate) fn new() -> Self { ClashingExternDeclarations { seen_decls: FxHashMap::default() } } + /// Insert a new foreign item into the seen set. If a symbol with the same name already exists /// for the item, return its HirId without updating the set. - fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> { + fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<hir::OwnerId> { let did = fi.owner_id.to_def_id(); let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); let name = Symbol::intern(tcx.symbol_name(instance).name); - if let Some(&hir_id) = self.seen_decls.get(&name) { + if let Some(&existing_id) = self.seen_decls.get(&name) { // Avoid updating the map with the new entry when we do find a collision. We want to // make sure we're always pointing to the first definition as the previous declaration. // This lets us avoid emitting "knock-on" diagnostics. - Some(hir_id) + Some(existing_id) } else { - self.seen_decls.insert(name, fi.hir_id()) + self.seen_decls.insert(name, fi.owner_id) } } @@ -2830,8 +2865,8 @@ impl ClashingExternDeclarations { structurally_same_type_impl( seen_types, cx, - tcx.type_of(a_did), - tcx.type_of(b_did), + tcx.type_of(a_did).subst_identity(), + tcx.type_of(b_did).subst_identity(), ckind, ) }, @@ -2926,16 +2961,16 @@ impl ClashingExternDeclarations { impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]); impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { + #[instrument(level = "trace", skip(self, cx))] fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) { - trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi); if let ForeignItemKind::Fn(..) = this_fi.kind { let tcx = cx.tcx; - if let Some(existing_hid) = self.insert(tcx, this_fi) { - let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid)); - let this_decl_ty = tcx.type_of(this_fi.owner_id); + if let Some(existing_did) = self.insert(tcx, this_fi) { + let existing_decl_ty = tcx.type_of(existing_did).skip_binder(); + let this_decl_ty = tcx.type_of(this_fi.owner_id).subst_identity(); debug!( "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}", - existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty + existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty ); // Check that the declarations match. if !Self::structurally_same_type( @@ -2944,7 +2979,7 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { this_decl_ty, CItemKind::Declaration, ) { - let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner()); + let orig_fi = tcx.hir().expect_foreign_item(existing_did); let orig = Self::name_of_extern_decl(tcx, orig_fi); // We want to ensure that we use spans for both decls that include where the diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 8046cc21c..f5a711315 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -39,7 +39,7 @@ use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; -use rustc_span::lev_distance::find_best_match_for_name; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, Span}; use rustc_target::abi; @@ -487,7 +487,7 @@ impl LintStore { let mut groups: Vec<_> = self .lint_groups .iter() - .filter_map(|(k, LintGroup { depr, .. })| if depr.is_none() { Some(k) } else { None }) + .filter_map(|(k, LintGroup { depr, .. })| depr.is_none().then_some(k)) .collect(); groups.sort(); let groups = groups.iter().map(|k| Symbol::intern(k)); @@ -837,9 +837,17 @@ pub trait LintContext: Sized { (use_span, "'_".to_owned()) }; debug!(?deletion_span, ?use_span); + + // issue 107998 for the case such as a wrong function pointer type + // `deletion_span` is empty and there is no need to report lifetime uses here + let suggestions = if deletion_span.is_empty() { + vec![(use_span, replace_lt)] + } else { + vec![(deletion_span, String::new()), (use_span, replace_lt)] + }; db.multipart_suggestion( msg, - vec![(deletion_span, String::new()), (use_span, replace_lt)], + suggestions, Applicability::MachineApplicable, ); } @@ -882,6 +890,26 @@ pub trait LintContext: Sized { ); } } + BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => { + db.help("consider implementing the trait by hand, or remove the `packed` attribute"); + } + BuiltinLintDiagnostics::UnusedExternCrate { removal_span }=> { + db.span_suggestion( + removal_span, + "remove it", + "", + Applicability::MachineApplicable, + ); + } + BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span }=> { + let suggestion_span = vis_span.between(ident_span); + db.span_suggestion_verbose( + suggestion_span, + "convert it to a `use`", + if vis_span.is_empty() { "use " } else { " use " }, + Applicability::MachineApplicable, + ); + } } // Rewrap `db`, and pass control to the user. decorate(db) @@ -1101,11 +1129,9 @@ impl<'tcx> LateContext<'tcx> { .maybe_typeck_results() .filter(|typeck_results| typeck_results.hir_owner == id.owner) .or_else(|| { - if self.tcx.has_typeck_results(id.owner.to_def_id()) { - Some(self.tcx.typeck(id.owner.def_id)) - } else { - None - } + self.tcx + .has_typeck_results(id.owner.to_def_id()) + .then(|| self.tcx.typeck(id.owner.def_id)) }) .and_then(|typeck_results| typeck_results.type_dependent_def(id)) .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index a45d8156c..ccf95992a 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { // `Deref` is being implemented for `t` if let hir::ItemKind::Impl(impl_) = item.kind && let Some(trait_) = &impl_.of_trait - && let t = cx.tcx.type_of(item.owner_id) + && let t = cx.tcx.type_of(item.owner_id).subst_identity() && let opt_did @ Some(did) = trait_.trait_def_id() && opt_did == cx.tcx.lang_items().deref_trait() // `t` is `dyn t_principal` diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index 73bd41732..f1ba192f2 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -4,7 +4,7 @@ use crate::{ LateContext, LateLintPass, }; use rustc_hir as hir; -use rustc_middle::ty::{visit::TypeVisitable, Ty}; +use rustc_middle::ty::{visit::TypeVisitableExt, Ty}; use rustc_span::{symbol::sym, Span}; declare_lint! { diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index f3ae26091..9af5284df 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,6 +1,6 @@ +use crate::fluent_generated as fluent; use rustc_errors::{ - fluent, AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic, - SubdiagnosticMessage, + AddToDiagnostic, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic, SubdiagnosticMessage, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::lint::Level; @@ -116,7 +116,7 @@ impl IntoDiagnostic<'_> for CheckNameUnknown { let mut diag = handler.struct_err(fluent::lint_check_name_unknown); diag.code(rustc_errors::error_code!(E0602)); if let Some(suggestion) = self.suggestion { - diag.help(fluent::help); + diag.help(fluent::lint_help); diag.set_arg("suggestion", suggestion); } diag.set_arg("lint_name", self.lint_name); diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index 5219992ee..a3367ae4a 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -65,11 +65,8 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { } else { ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var } } ; - let question_mark = if suggest_question_mark(cx, adt, substs, expr.span) { - Some(ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() }) - } else { - None - }; + let question_mark = suggest_question_mark(cx, adt, substs, expr.span) + .then(|| ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() }); let suggestion = ForLoopsOverFalliblesSuggestion { var, start_span: expr.span.with_hi(pat.span.lo()), @@ -139,9 +136,10 @@ fn suggest_question_mark<'tcx>( let ty = substs.type_at(0); let infcx = cx.tcx.infer_ctxt().build(); + let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); let cause = ObligationCause::new( span, - body_id.hir_id, + body_def_id, rustc_infer::traits::ObligationCauseCode::MiscObligation, ); let errors = rustc_trait_selection::traits::fully_solve_bound( diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 6cefaea2b..2fd0ef3cd 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -216,7 +216,7 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &Path<'_>) -> Option<String> { } // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => { - if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).subst_identity().kind() { if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did()) { // NOTE: This path is currently unreachable as `Ty<'tcx>` is diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b2a265674..b42878a02 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -66,13 +66,12 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { self.context.last_node_with_lint_attrs = prev; } - fn with_param_env<F>(&mut self, id: hir::HirId, f: F) + fn with_param_env<F>(&mut self, id: hir::OwnerId, f: F) where F: FnOnce(&mut Self), { let old_param_env = self.context.param_env; - self.context.param_env = - self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id)); + self.context.param_env = self.context.tcx.param_env(id); f(self); self.context.param_env = old_param_env; } @@ -132,7 +131,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let old_cached_typeck_results = self.context.cached_typeck_results.take(); let old_enclosing_body = self.context.enclosing_body.take(); self.with_lint_attrs(it.hir_id(), |cx| { - cx.with_param_env(it.hir_id(), |cx| { + cx.with_param_env(it.owner_id, |cx| { lint_callback!(cx, check_item, it); hir_visit::walk_item(cx, it); lint_callback!(cx, check_item_post, it); @@ -145,7 +144,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { self.with_lint_attrs(it.hir_id(), |cx| { - cx.with_param_env(it.hir_id(), |cx| { + cx.with_param_env(it.owner_id, |cx| { lint_callback!(cx, check_foreign_item, it); hir_visit::walk_foreign_item(cx, it); }); @@ -180,7 +179,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas decl: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, span: Span, - id: hir::HirId, + id: LocalDefId, ) { // Wrap in typeck results here, not just in visit_nested_body, // in order for `check_fn` to be able to use them. @@ -268,7 +267,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let generics = self.context.generics.take(); self.context.generics = Some(&trait_item.generics); self.with_lint_attrs(trait_item.hir_id(), |cx| { - cx.with_param_env(trait_item.hir_id(), |cx| { + cx.with_param_env(trait_item.owner_id, |cx| { lint_callback!(cx, check_trait_item, trait_item); hir_visit::walk_trait_item(cx, trait_item); }); @@ -280,7 +279,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas let generics = self.context.generics.take(); self.context.generics = Some(&impl_item.generics); self.with_lint_attrs(impl_item.hir_id(), |cx| { - cx.with_param_env(impl_item.hir_id(), |cx| { + cx.with_param_env(impl_item.owner_id, |cx| { lint_callback!(cx, check_impl_item, impl_item); hir_visit::walk_impl_item(cx, impl_item); lint_callback!(cx, check_impl_item_post, impl_item); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index cca36913d..bc7488fab 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,13 +1,16 @@ -use crate::context::{CheckLintNameResult, LintStore}; -use crate::late::unerased_lint_store; -use crate::lints::{ - DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, RenamedOrRemovedLint, - RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion, +use crate::{ + context::{CheckLintNameResult, LintStore}, + fluent_generated as fluent, + late::unerased_lint_store, + lints::{ + DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAtributeLint, + RenamedOrRemovedLint, RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion, + }, }; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{fluent, DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; +use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; @@ -983,7 +986,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { fluent::lint_unknown_gated_lint, |lint| { lint.set_arg("name", lint_id.lint.name_lower()); - lint.note(fluent::note); + lint.note(fluent::lint_note); add_feature_diagnostics(lint, &self.sess.parse_sess, feature); lint }, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d6be4da03..35dc533e5 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -63,7 +63,9 @@ mod late; mod let_underscore; mod levels; mod lints; +mod map_unit_fn; mod methods; +mod multiple_supertrait_upcastable; mod non_ascii_idents; mod non_fmt_panic; mod nonstandard_style; @@ -79,8 +81,10 @@ mod unused; pub use array_into_iter::ARRAY_INTO_ITER; use rustc_ast as ast; +use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; 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::ty::TyCtxt; use rustc_session::lint::builtin::{ @@ -97,7 +101,9 @@ use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use internal::*; use let_underscore::*; +use map_unit_fn::*; use methods::*; +use multiple_supertrait_upcastable::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; use nonstandard_style::*; @@ -120,6 +126,8 @@ pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId}; pub use rustc_session::lint::{LintArray, LintPass}; +fluent_messages! { "../locales/en-US.ftl" } + pub fn provide(providers: &mut Providers) { levels::provide(providers); expect::provide(providers); @@ -232,6 +240,8 @@ late_lint_methods!( InvalidAtomicOrdering: InvalidAtomicOrdering, NamedAsmLabels: NamedAsmLabels, OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, + MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, + MapUnitFn: MapUnitFn, ] ] ); @@ -291,7 +301,8 @@ fn register_builtins(store: &mut LintStore) { UNUSED_LABELS, UNUSED_PARENS, UNUSED_BRACES, - REDUNDANT_SEMICOLONS + REDUNDANT_SEMICOLONS, + MAP_UNIT_FN ); add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK); @@ -321,7 +332,6 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); - store.register_renamed("safe_packed_borrows", "unaligned_references"); store.register_renamed("disjoint_capture_migration", "rust_2021_incompatible_closure_captures"); store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns"); store.register_renamed("non_fmt_panic", "non_fmt_panics"); @@ -484,6 +494,16 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see issue #71800 \ <https://github.com/rust-lang/rust/issues/71800> for more information", ); + store.register_removed( + "safe_packed_borrows", + "converted into hard error, see issue #82523 \ + <https://github.com/rust-lang/rust/issues/82523> for more information", + ); + store.register_removed( + "unaligned_references", + "converted into hard error, see issue #82523 \ + <https://github.com/rust-lang/rust/issues/82523> for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 329ece28e..20ab0af58 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2,13 +2,16 @@ #![allow(rustc::diagnostic_outside_of_impl)] use std::num::NonZeroU32; +use crate::fluent_generated as fluent; use rustc_errors::{ - fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, - DiagnosticStyledString, SuggestionStyle, + AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, DiagnosticStyledString, + SuggestionStyle, }; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::{PolyExistentialTraitRef, Predicate, Ty, TyCtxt}; +use rustc_middle::ty::{ + inhabitedness::InhabitedPredicate, PolyExistentialTraitRef, Predicate, Ty, TyCtxt, +}; use rustc_session::parse::ParseSess; use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol}; @@ -21,7 +24,7 @@ use crate::{ #[diag(lint_array_into_iter)] pub struct ArrayIntoIterDiag<'a> { pub target: &'a str, - #[suggestion(use_iter_suggestion, code = "iter", applicability = "machine-applicable")] + #[suggestion(lint_use_iter_suggestion, code = "iter", applicability = "machine-applicable")] pub suggestion: Span, #[subdiagnostic] pub sub: Option<ArrayIntoIterDiagSub>, @@ -29,12 +32,15 @@ pub struct ArrayIntoIterDiag<'a> { #[derive(Subdiagnostic)] pub enum ArrayIntoIterDiagSub { - #[suggestion(remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")] + #[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")] RemoveIntoIter { #[primary_span] span: Span, }, - #[multipart_suggestion(use_explicit_into_iter_suggestion, applicability = "maybe-incorrect")] + #[multipart_suggestion( + lint_use_explicit_into_iter_suggestion, + applicability = "maybe-incorrect" + )] UseExplicitIntoIter { #[suggestion_part(code = "IntoIterator::into_iter(")] start_span: Span, @@ -161,13 +167,13 @@ pub struct BuiltinDeprecatedAttrLink<'a> { #[derive(Subdiagnostic)] pub enum BuiltinDeprecatedAttrLinkSuggestion<'a> { - #[suggestion(msg_suggestion, code = "", applicability = "machine-applicable")] + #[suggestion(lint_msg_suggestion, code = "", applicability = "machine-applicable")] Msg { #[primary_span] suggestion: Span, msg: &'a str, }, - #[suggestion(default_suggestion, code = "", applicability = "machine-applicable")] + #[suggestion(lint_default_suggestion, code = "", applicability = "machine-applicable")] Default { #[primary_span] suggestion: Span, @@ -199,9 +205,9 @@ pub struct BuiltinUnusedDocComment<'a> { #[derive(Subdiagnostic)] pub enum BuiltinUnusedDocCommentSub { - #[help(plain_help)] + #[help(lint_plain_help)] PlainHelp, - #[help(block_help)] + #[help(lint_block_help)] BlockHelp, } @@ -240,7 +246,7 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { - diag.span_label(self.label, fluent::label); + diag.span_label(self.label, fluent::lint_label); rustc_session::parse::add_feature_diagnostics( diag, &self.parse_sess, @@ -335,7 +341,7 @@ impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { ) -> rustc_errors::SubdiagnosticMessage, { diag.multipart_suggestion( - fluent::suggestion, + fluent::lint_suggestion, self.suggestions, Applicability::MachineApplicable, ); @@ -386,7 +392,7 @@ pub struct BuiltinExplicitOutlives { } #[derive(Subdiagnostic)] -#[multipart_suggestion(suggestion)] +#[multipart_suggestion(lint_suggestion)] pub struct BuiltinExplicitOutlivesSuggestion { #[suggestion_part(code = "")] pub spans: Vec<Span>, @@ -405,11 +411,11 @@ pub struct BuiltinIncompleteFeatures { } #[derive(Subdiagnostic)] -#[help(help)] +#[help(lint_help)] pub struct BuiltinIncompleteFeaturesHelp; #[derive(Subdiagnostic)] -#[note(note)] +#[note(lint_note)] pub struct BuiltinIncompleteFeaturesNote { pub n: NonZeroU32, } @@ -419,6 +425,7 @@ pub struct BuiltinUnpermittedTypeInit<'a> { pub ty: Ty<'a>, pub label: Span, pub sub: BuiltinUnpermittedTypeInitSub, + pub tcx: TyCtxt<'a>, } impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { @@ -428,7 +435,13 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { diag.set_arg("ty", self.ty); diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label); - diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label_suggestion); + if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) { + // Only suggest late `MaybeUninit::assume_init` initialization if the type is inhabited. + diag.span_label( + self.label, + fluent::lint_builtin_unpermitted_type_init_label_suggestion, + ); + } self.sub.add_to_diagnostic(diag); diag } @@ -473,9 +486,9 @@ pub enum BuiltinClashingExtern<'a> { SameName { this: Symbol, orig: Symbol, - #[label(previous_decl_label)] + #[label(lint_previous_decl_label)] previous_decl_label: Span, - #[label(mismatch_label)] + #[label(lint_mismatch_label)] mismatch_label: Span, #[subdiagnostic] sub: BuiltinClashingExternSub<'a>, @@ -484,9 +497,9 @@ pub enum BuiltinClashingExtern<'a> { DiffName { this: Symbol, orig: Symbol, - #[label(previous_decl_label)] + #[label(lint_previous_decl_label)] previous_decl_label: Span, - #[label(mismatch_label)] + #[label(lint_mismatch_label)] mismatch_label: Span, #[subdiagnostic] sub: BuiltinClashingExternSub<'a>, @@ -562,7 +575,7 @@ pub struct SupertraitAsDerefTarget<'a> { } #[derive(Subdiagnostic)] -#[label(label)] +#[label(lint_label)] pub struct SupertraitAsDerefTargetLabel { #[primary_span] pub label: Span, @@ -595,7 +608,7 @@ pub struct Expectation { } #[derive(Subdiagnostic)] -#[note(rationale)] +#[note(lint_rationale)] pub struct ExpectationNote { pub rationale: Symbol, } @@ -616,13 +629,13 @@ pub struct ForLoopsOverFalliblesDiag<'a> { #[derive(Subdiagnostic)] pub enum ForLoopsOverFalliblesLoopSub<'a> { - #[suggestion(remove_next, code = ".by_ref()", applicability = "maybe-incorrect")] + #[suggestion(lint_remove_next, code = ".by_ref()", applicability = "maybe-incorrect")] RemoveNext { #[primary_span] suggestion: Span, recv_snip: String, }, - #[multipart_suggestion(use_while_let, applicability = "maybe-incorrect")] + #[multipart_suggestion(lint_use_while_let, applicability = "maybe-incorrect")] UseWhileLet { #[suggestion_part(code = "while let {var}(")] start_span: Span, @@ -633,14 +646,14 @@ pub enum ForLoopsOverFalliblesLoopSub<'a> { } #[derive(Subdiagnostic)] -#[suggestion(use_question_mark, code = "?", applicability = "maybe-incorrect")] +#[suggestion(lint_use_question_mark, code = "?", applicability = "maybe-incorrect")] pub struct ForLoopsOverFalliblesQuestionMark { #[primary_span] pub suggestion: Span, } #[derive(Subdiagnostic)] -#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")] +#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")] pub struct ForLoopsOverFalliblesSuggestion<'a> { pub var: &'a str, #[suggestion_part(code = "if let {var}(")] @@ -699,13 +712,13 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( - fluent::suggestion_remove, + fluent::lint_suggestion_remove, spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); diag.multipart_suggestion( - fluent::suggestion_escape, + fluent::lint_suggestion_escape, spans .into_iter() .map(|(c, span)| { @@ -728,13 +741,29 @@ impl AddToDiagnostic for HiddenUnicodeCodepointsDiagSub { .collect::<Vec<String>>() .join(", "), ); - diag.note(fluent::suggestion_remove); - diag.note(fluent::no_suggestion_note_escape); + diag.note(fluent::lint_suggestion_remove); + diag.note(fluent::lint_no_suggestion_note_escape); } } } } +// map_unit_fn.rs +#[derive(LintDiagnostic)] +#[diag(lint_map_unit_fn)] +#[note] +pub struct MappingToUnit { + #[label(lint_function_label)] + pub function_label: Span, + #[label(lint_argument_label)] + pub argument_label: Span, + #[label(lint_map_label)] + pub map_label: Span, + #[suggestion(style = "verbose", code = "{replace}", applicability = "maybe-incorrect")] + pub suggestion: Span, + pub replace: String, +} + // internal.rs #[derive(LintDiagnostic)] #[diag(lint_default_hash_types)] @@ -874,7 +903,7 @@ pub struct RenamedOrRemovedLint<'a> { } #[derive(Subdiagnostic)] -#[suggestion(suggestion, code = "{replace}", applicability = "machine-applicable")] +#[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")] pub struct RenamedOrRemovedLintSuggestion<'a> { #[primary_span] pub suggestion: Span, @@ -890,7 +919,7 @@ pub struct UnknownLint { } #[derive(Subdiagnostic)] -#[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] +#[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] pub struct UnknownLintSuggestion { #[primary_span] pub suggestion: Span, @@ -910,12 +939,19 @@ pub struct IgnoredUnlessCrateSpecified<'a> { #[note] #[help] pub struct CStringPtr { - #[label(as_ptr_label)] + #[label(lint_as_ptr_label)] pub as_ptr: Span, - #[label(unwrap_label)] + #[label(lint_unwrap_label)] pub unwrap: Span, } +// multiple_supertrait_upcastable.rs +#[derive(LintDiagnostic)] +#[diag(lint_multple_supertrait_upcastable)] +pub struct MultipleSupertraitUpcastable { + pub ident: Ident, +} + // non_ascii_idents.rs #[derive(LintDiagnostic)] #[diag(lint_identifier_non_ascii_char)] @@ -936,7 +972,7 @@ pub struct ConfusableIdentifierPair { #[derive(LintDiagnostic)] #[diag(lint_mixed_script_confusables)] -#[note(includes_note)] +#[note(lint_includes_note)] #[note] pub struct MixedScriptConfusables { pub set: String, @@ -956,17 +992,17 @@ impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused { diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { diag.set_arg("count", self.count); - diag.note(fluent::note); + diag.note(fluent::lint_note); if let Some(span) = self.suggestion { diag.span_suggestion( span.shrink_to_hi(), - fluent::add_args_suggestion, + fluent::lint_add_args_suggestion, ", ...", Applicability::HasPlaceholders, ); diag.span_suggestion( span.shrink_to_lo(), - fluent::add_fmt_suggestion, + fluent::lint_add_fmt_suggestion, "\"{}\", ", Applicability::MachineApplicable, ); @@ -1000,12 +1036,12 @@ pub struct NonCamelCaseType<'a> { #[derive(Subdiagnostic)] pub enum NonCamelCaseTypeSub { - #[label(label)] + #[label(lint_label)] Label { #[primary_span] span: Span, }, - #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] + #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] Suggestion { #[primary_span] span: Span, @@ -1041,15 +1077,15 @@ impl AddToDiagnostic for NonSnakeCaseDiagSub { { match self { NonSnakeCaseDiagSub::Label { span } => { - diag.span_label(span, fluent::label); + diag.span_label(span, fluent::lint_label); } NonSnakeCaseDiagSub::Help => { - diag.help(fluent::help); + diag.help(fluent::lint_help); } NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => { diag.span_suggestion( span, - fluent::convert_suggestion, + fluent::lint_convert_suggestion, suggestion, Applicability::MaybeIncorrect, ); @@ -1057,16 +1093,16 @@ impl AddToDiagnostic for NonSnakeCaseDiagSub { NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => { diag.span_suggestion( span, - fluent::rename_or_convert_suggestion, + fluent::lint_rename_or_convert_suggestion, suggestion, Applicability::MaybeIncorrect, ); } NonSnakeCaseDiagSub::SuggestionAndNote { span } => { - diag.note(fluent::cannot_convert_note); + diag.note(fluent::lint_cannot_convert_note); diag.span_suggestion( span, - fluent::rename_suggestion, + fluent::lint_rename_suggestion, "", Applicability::MaybeIncorrect, ); @@ -1086,12 +1122,12 @@ pub struct NonUpperCaseGlobal<'a> { #[derive(Subdiagnostic)] pub enum NonUpperCaseGlobalSub { - #[label(label)] + #[label(lint_label)] Label { #[primary_span] span: Span, }, - #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")] + #[suggestion(lint_suggestion, code = "{replace}", applicability = "maybe-incorrect")] Suggestion { #[primary_span] span: Span, @@ -1209,11 +1245,11 @@ impl AddToDiagnostic for OverflowingBinHexSign { { match self { OverflowingBinHexSign::Positive => { - diag.note(fluent::positive_note); + diag.note(fluent::lint_positive_note); } OverflowingBinHexSign::Negative => { - diag.note(fluent::negative_note); - diag.note(fluent::negative_becomes_note); + diag.note(fluent::lint_negative_note); + diag.note(fluent::lint_negative_becomes_note); } } } @@ -1222,7 +1258,7 @@ impl AddToDiagnostic for OverflowingBinHexSign { #[derive(Subdiagnostic)] pub enum OverflowingBinHexSub<'a> { #[suggestion( - suggestion, + lint_suggestion, code = "{sans_suffix}{suggestion_ty}", applicability = "machine-applicable" )] @@ -1232,7 +1268,7 @@ pub enum OverflowingBinHexSub<'a> { suggestion_ty: &'a str, sans_suffix: &'a str, }, - #[help(help)] + #[help(lint_help)] Help { suggestion_ty: &'a str }, } @@ -1249,7 +1285,7 @@ pub struct OverflowingInt<'a> { } #[derive(Subdiagnostic)] -#[help(help)] +#[help(lint_help)] pub struct OverflowingIntHelp<'a> { pub suggestion_ty: &'a str, } @@ -1301,13 +1337,13 @@ impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> { ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { diag.set_arg("ty", self.ty); diag.set_arg("desc", self.desc); - diag.span_label(self.label, fluent::label); + diag.span_label(self.label, fluent::lint_label); if let Some(help) = self.help { diag.help(help); } diag.note(self.note); if let Some(note) = self.span_note { - diag.span_note(note, fluent::note); + diag.span_note(note, fluent::lint_note); } diag } @@ -1394,6 +1430,21 @@ pub struct UnusedDef<'a, 'b> { pub cx: &'a LateContext<'b>, pub def_id: DefId, pub note: Option<Symbol>, + pub suggestion: Option<UnusedDefSuggestion>, +} + +#[derive(Subdiagnostic)] +pub enum UnusedDefSuggestion { + #[suggestion( + lint_suggestion, + style = "verbose", + code = "let _ = ", + applicability = "machine-applicable" + )] + Default { + #[primary_span] + span: Span, + }, } // Needed because of def_path_str @@ -1409,6 +1460,9 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> { if let Some(note) = self.note { diag.note(note.as_str()); } + if let Some(sugg) = self.suggestion { + diag.subdiagnostic(sugg); + } diag } @@ -1426,13 +1480,13 @@ pub struct PathStatementDrop { #[derive(Subdiagnostic)] pub enum PathStatementDropSub { - #[suggestion(suggestion, code = "drop({snippet});", applicability = "machine-applicable")] + #[suggestion(lint_suggestion, code = "drop({snippet});", applicability = "machine-applicable")] Suggestion { #[primary_span] span: Span, snippet: String, }, - #[help(help)] + #[help(lint_help)] Help { #[primary_span] span: Span, @@ -1453,7 +1507,7 @@ pub struct UnusedDelim<'a> { } #[derive(Subdiagnostic)] -#[multipart_suggestion(suggestion, applicability = "machine-applicable")] +#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")] pub struct UnusedDelimSuggestion { #[suggestion_part(code = "{start_replace}")] pub start_span: Span, diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs new file mode 100644 index 000000000..62e8b4fe9 --- /dev/null +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -0,0 +1,120 @@ +use crate::lints::MappingToUnit; +use crate::{LateContext, LateLintPass, LintContext}; + +use rustc_hir::{Expr, ExprKind, HirId, Stmt, StmtKind}; +use rustc_middle::{ + query::Key, + ty::{self, Ty}, +}; + +declare_lint! { + /// The `map_unit_fn` lint checks for `Iterator::map` receive + /// a callable that returns `()`. + /// + /// ### Example + /// + /// ```rust + /// fn foo(items: &mut Vec<u8>) { + /// items.sort(); + /// } + /// + /// fn main() { + /// let mut x: Vec<Vec<u8>> = vec![ + /// vec![0, 2, 1], + /// vec![5, 4, 3], + /// ]; + /// x.iter_mut().map(foo); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Mapping to `()` is almost always a mistake. + pub MAP_UNIT_FN, + Warn, + "`Iterator::map` call that discard the iterator's values" +} + +declare_lint_pass!(MapUnitFn => [MAP_UNIT_FN]); + +impl<'tcx> LateLintPass<'tcx> for MapUnitFn { + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) { + if stmt.span.from_expansion() { + return; + } + + if let StmtKind::Semi(expr) = stmt.kind { + if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind { + if path.ident.name.as_str() == "map" { + if receiver.span.from_expansion() + || args.iter().any(|e| e.span.from_expansion()) + || !is_impl_slice(cx, receiver) + || !is_diagnostic_name(cx, expr.hir_id, "IteratorMap") + { + return; + } + let arg_ty = cx.typeck_results().expr_ty(&args[0]); + if let ty::FnDef(id, _) = arg_ty.kind() { + let fn_ty = cx.tcx.fn_sig(id).skip_binder(); + let ret_ty = fn_ty.output().skip_binder(); + if is_unit_type(ret_ty) { + cx.emit_spanned_lint( + MAP_UNIT_FN, + span, + MappingToUnit { + function_label: cx.tcx.span_of_impl(*id).unwrap(), + argument_label: args[0].span, + map_label: arg_ty.default_span(cx.tcx), + suggestion: path.ident.span, + replace: "for_each".to_string(), + }, + ) + } + } else if let ty::Closure(id, subs) = arg_ty.kind() { + let cl_ty = subs.as_closure().sig(); + let ret_ty = cl_ty.output().skip_binder(); + if is_unit_type(ret_ty) { + cx.emit_spanned_lint( + MAP_UNIT_FN, + span, + MappingToUnit { + function_label: cx.tcx.span_of_impl(*id).unwrap(), + argument_label: args[0].span, + map_label: arg_ty.default_span(cx.tcx), + suggestion: path.ident.span, + replace: "for_each".to_string(), + }, + ) + } + } + } + } + } + } +} + +fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + if let Some(impl_id) = cx.tcx.impl_of_method(method_id) { + return cx.tcx.type_of(impl_id).skip_binder().is_slice(); + } + } + false +} + +fn is_unit_type(ty: Ty<'_>) -> bool { + ty.is_unit() || ty.is_never() +} + +fn is_diagnostic_name(cx: &LateContext<'_>, id: HirId, name: &str) -> bool { + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id) { + if let Some(item) = cx.tcx.get_diagnostic_name(def_id) { + if item.as_str() == name { + return true; + } + } + } + false +} diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs new file mode 100644 index 000000000..c2ed0e19f --- /dev/null +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -0,0 +1,60 @@ +use crate::{LateContext, LateLintPass, LintContext}; + +use rustc_hir as hir; +use rustc_span::sym; + +declare_lint! { + /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple + /// supertraits. + /// + /// ### Example + /// + /// ```rust + /// trait A {} + /// trait B {} + /// + /// #[warn(multiple_supertrait_upcastable)] + /// trait C: A + B {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To support upcasting with multiple supertraits, we need to store multiple vtables and this + /// can result in extra space overhead, even if no code actually uses upcasting. + /// This lint allows users to identify when such scenarios occur and to decide whether the + /// additional overhead is justified. + pub MULTIPLE_SUPERTRAIT_UPCASTABLE, + Allow, + "detect when an object-safe trait has multiple supertraits", + @feature_gate = sym::multiple_supertrait_upcastable; +} + +declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]); + +impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + let def_id = item.owner_id.to_def_id(); + // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because + // the latter will report `where_clause_object_safety` lint. + if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind + && cx.tcx.object_safety_violations(def_id).is_empty() + { + let direct_super_traits_iter = cx.tcx + .super_predicates_of(def_id) + .predicates + .into_iter() + .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred()); + if direct_super_traits_iter.count() > 1 { + cx.emit_spanned_lint( + MULTIPLE_SUPERTRAIT_UPCASTABLE, + cx.tcx.def_span(def_id), + crate::lints::MultipleSupertraitUpcastable { + ident: item.ident + }, + ); + } + } + } +} diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 4a02c6cce..5bb1abfd2 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -1,7 +1,7 @@ use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused}; -use crate::{LateContext, LateLintPass, LintContext}; +use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; -use rustc_errors::{fluent, Applicability}; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::lint::in_external_macro; @@ -122,18 +122,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc #[allow(rustc::diagnostic_outside_of_impl)] cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint_non_fmt_panic, |lint| { lint.set_arg("name", symbol); - lint.note(fluent::note); - lint.note(fluent::more_info_note); + lint.note(fluent::lint_note); + lint.note(fluent::lint_more_info_note); if !is_arg_inside_call(arg_span, span) { // 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)) { // A case of `panic!(format!(..))`. - lint.note(fluent::supports_fmt_note); + lint.note(fluent::lint_supports_fmt_note); if let Some((open, close, _)) = find_delimiters(cx, arg_span) { lint.multipart_suggestion( - fluent::supports_fmt_suggestion, + fluent::lint_supports_fmt_suggestion, vec![ (arg_span.until(open.shrink_to_hi()), "".into()), (close.until(arg_span.shrink_to_hi()), "".into()), @@ -146,7 +146,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc // If this is a &str or String, we can confidently give the `"{}", ` suggestion. let is_str = matches!( ty.kind(), - ty::Ref(_, r, _) if *r.kind() == ty::Str, + ty::Ref(_, r, _) if r.is_str(), ) || matches!( ty.ty_adt_def(), Some(ty_def) if Some(ty_def.did()) == cx.tcx.lang_items().string(), @@ -179,7 +179,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if suggest_display { lint.span_suggestion_verbose( arg_span.shrink_to_lo(), - fluent::display_suggestion, + fluent::lint_display_suggestion, "\"{}\", ", fmt_applicability, ); @@ -187,7 +187,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc lint.set_arg("ty", ty); lint.span_suggestion_verbose( arg_span.shrink_to_lo(), - fluent::debug_suggestion, + fluent::lint_debug_suggestion, "\"{:?}\", ", fmt_applicability, ); @@ -197,7 +197,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc if let Some((open, close, del)) = find_delimiters(cx, span) { lint.set_arg("already_suggested", suggest_display || suggest_debug); lint.multipart_suggestion( - fluent::panic_suggestion, + fluent::lint_panic_suggestion, if del == '(' { vec![(span.until(open), "std::panic::panic_any".into())] } else { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 74d234fab..71e2e66bd 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -10,8 +10,9 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; use rustc_hir::{GenericParamKind, PatKind}; use rustc_middle::ty; -use rustc_span::symbol::sym; -use rustc_span::{symbol::Ident, BytePos, Span}; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; #[derive(PartialEq)] @@ -21,9 +22,8 @@ pub enum MethodLateContext { PlainImpl, } -pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext { - let def_id = cx.tcx.hir().local_def_id(id); - let item = cx.tcx.associated_item(def_id); +pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext { + let item = cx.tcx.associated_item(id); match item.container { ty::TraitContainer => MethodLateContext::TraitAutoImpl, ty::ImplContainer => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) { @@ -379,13 +379,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { _: &hir::FnDecl<'_>, _: &hir::Body<'_>, _: Span, - id: hir::HirId, + id: LocalDefId, ) { - let attrs = cx.tcx.hir().attrs(id); match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) + if sig.header.abi != Abi::Rust + && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { return; } @@ -398,7 +398,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) { + if header.abi != Abi::Rust && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 42442cfb1..883a56cb3 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { struct OpaqueHiddenInferredBoundLint<'tcx> { ty: Ty<'tcx>, proj_ty: Ty<'tcx>, - #[label(specifically)] + #[label(lint_specifically)] assoc_pred_span: Span, #[subdiagnostic] add_bound: Option<AddBound<'tcx>>, diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 392e13f2f..2bb2a3aab 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -50,7 +50,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri return Some(format!("{}{}", name, gen_args(cx, path_segment))); } Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => { - if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { + if let ty::Adt(adt, substs) = cx.tcx.type_of(did).subst_identity().kind() { if cx.tcx.has_attr(adt.did(), sym::rustc_pass_by_value) { return Some(cx.tcx.def_path_str_with_substs(adt.did(), substs)); } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 0bf01c4e5..16964565b 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -4,6 +4,7 @@ use rustc_ast as ast; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; use rustc_session::lint::LintPass; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -36,7 +37,7 @@ macro_rules! late_lint_methods { b: &'tcx hir::FnDecl<'tcx>, c: &'tcx hir::Body<'tcx>, d: Span, - e: hir::HirId); + e: LocalDefId); fn check_trait_item(a: &'tcx hir::TraitItem<'tcx>); fn check_impl_item(a: &'tcx hir::ImplItem<'tcx>); fn check_impl_item_post(a: &'tcx hir::ImplItem<'tcx>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index be47a3e23..85958c417 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,19 +1,25 @@ -use crate::lints::{ - AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, - InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, - OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, - RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag, +use crate::{ + fluent_generated as fluent, + lints::{ + AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, + InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, + OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, + OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag, + }, }; use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{fluent, DiagnosticMessage}; +use rustc_errors::DiagnosticMessage; use rustc_hir as hir; use rustc_hir::{is_range_literal, Expr, ExprKind, Node}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::{ + self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, +}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -650,7 +656,7 @@ pub fn transparent_newtype_field<'a, 'tcx>( ) -> Option<&'a ty::FieldDef> { let param_env = tcx.param_env(variant.def_id); variant.fields.iter().find(|field| { - let field_ty = tcx.type_of(field.did); + 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()); !is_zst }) @@ -1107,6 +1113,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) | ty::Placeholder(..) | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), } @@ -1142,7 +1149,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { struct ProhibitOpaqueTypes; - impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes { + impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -1223,9 +1230,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) { - let def_id = self.cx.tcx.hir().local_def_id(id); - let sig = self.cx.tcx.fn_sig(def_id); + fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &hir::FnDecl<'_>) { + let sig = self.cx.tcx.fn_sig(def_id).subst_identity(); let sig = self.cx.tcx.erase_late_bound_regions(sig); for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { @@ -1238,9 +1244,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - fn check_foreign_static(&mut self, id: hir::HirId, span: Span) { - let def_id = self.cx.tcx.hir().local_def_id(id); - let ty = self.cx.tcx.type_of(def_id); + fn check_foreign_static(&mut self, id: hir::OwnerId, span: Span) { + let ty = self.cx.tcx.type_of(id).subst_identity(); self.check_type_for_ffi_and_report_errors(span, ty, true, false); } @@ -1260,10 +1265,10 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { if !vis.is_internal_abi(abi) { match it.kind { hir::ForeignItemKind::Fn(ref decl, _, _) => { - vis.check_foreign_fn(it.hir_id(), decl); + vis.check_foreign_fn(it.owner_id.def_id, decl); } hir::ForeignItemKind::Static(ref ty, _) => { - vis.check_foreign_static(it.hir_id(), ty.span); + vis.check_foreign_static(it.owner_id, ty.span); } hir::ForeignItemKind::Type => (), } @@ -1279,7 +1284,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { decl: &'tcx hir::FnDecl<'_>, _: &'tcx hir::Body<'_>, _: Span, - hir_id: hir::HirId, + id: LocalDefId, ) { use hir::intravisit::FnKind; @@ -1291,7 +1296,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition }; if !vis.is_internal_abi(abi) { - vis.check_foreign_fn(hir_id, decl); + vis.check_foreign_fn(id, decl); } } } @@ -1301,7 +1306,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]); impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind { - let t = cx.tcx.type_of(it.owner_id); + let t = cx.tcx.type_of(it.owner_id).subst_identity(); let ty = cx.tcx.erase_regions(t); let Ok(layout) = cx.layout_of(ty) else { return }; let Variants::Multiple { @@ -1421,7 +1426,7 @@ impl InvalidAtomicOrdering { && recognized_names.contains(&method_path.ident.name) && let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_did) = cx.tcx.impl_of_method(m_def_id) - && let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() + && let Some(adt) = cx.tcx.type_of(impl_did).subst_identity().ty_adt_def() // skip extension traits, only lint functions from the standard library && cx.tcx.trait_id_of_impl(impl_did).is_none() && let parent = cx.tcx.parent(adt.did()) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 4c9b3df2d..3a92f5806 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,7 +1,7 @@ use crate::lints::{ PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag, - UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDelim, UnusedDelimSuggestion, - UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult, + UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim, + UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult, }; use crate::Lint; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -309,7 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { None } } - ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) { + ty::Array(ty, len) => match len.try_eval_target_usize(cx.tcx, cx.param_env) { // If the array is empty we don't lint, to avoid false positives Some(0) | None => None, // If the array is definitely non-empty, we can do `#[must_use]` checking. @@ -418,6 +418,19 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ); } MustUsePath::Def(span, def_id, reason) => { + let suggestion = if matches!( + cx.tcx.get_diagnostic_name(*def_id), + Some(sym::add) + | Some(sym::sub) + | Some(sym::mul) + | Some(sym::div) + | Some(sym::rem) + | Some(sym::neg), + ) { + Some(UnusedDefSuggestion::Default { span: span.shrink_to_lo() }) + } else { + None + }; cx.emit_spanned_lint( UNUSED_MUST_USE, *span, @@ -427,6 +440,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx, def_id: *def_id, note: *reason, + suggestion, }, ); } @@ -495,6 +509,7 @@ enum UnusedDelimsCtx { ArrayLenExpr, AnonConst, MatchArmExpr, + IndexExpr, } impl From<UnusedDelimsCtx> for &'static str { @@ -514,6 +529,7 @@ impl From<UnusedDelimsCtx> for &'static str { UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression", UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression", UnusedDelimsCtx::MatchArmExpr => "match arm expression", + UnusedDelimsCtx::IndexExpr => "index expression", } } } @@ -661,6 +677,10 @@ trait UnusedDelimLint { keep_space: (bool, bool), ) { let primary_span = if let Some((lo, hi)) = spans { + if hi.is_empty() { + // do not point at delims that do not exist + return; + } MultiSpan::from(vec![lo, hi]) } else { MultiSpan::from(value_span) @@ -733,6 +753,8 @@ trait UnusedDelimLint { (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None) } + Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None), + Assign(_, ref value, _) | AssignOp(.., ref value) => { (value, UnusedDelimsCtx::AssignedValue, false, None, None) } |