diff options
Diffstat (limited to 'compiler/rustc_lint/src')
| -rw-r--r-- | compiler/rustc_lint/src/builtin.rs | 64 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/context.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/early.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/for_loops_over_fallibles.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/internal.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lints.rs | 54 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/map_unit_fn.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/nonstandard_style.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/types.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/unused.rs | 35 |
11 files changed, 157 insertions, 107 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5b2100b5da9..c1b247e3d61 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -58,7 +58,6 @@ 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, Node, PatKind, PredicateOrigin}; -use rustc_index::vec::Idx; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -69,7 +68,7 @@ use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; -use rustc_target::abi::{Abi, VariantIdx}; +use rustc_target::abi::{Abi, FIRST_VARIANT}; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; @@ -358,29 +357,29 @@ impl EarlyLintPass for UnsafeCode { } ast::ItemKind::Fn(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn); } } ast::ItemKind::Static(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic); } } @@ -391,10 +390,10 @@ impl EarlyLintPass for UnsafeCode { fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { if let ast::AssocItemKind::Fn(..) = it.kind { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod); } } @@ -1123,12 +1122,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn(.., ref generics, _) => { - if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) { + if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); } } hir::ItemKind::Const(..) => { - if cx.sess().contains_name(attrs, sym::no_mangle) { + if attr::contains_name(attrs, sym::no_mangle) { // account for "pub const" (#45562) let start = cx .tcx @@ -1152,9 +1151,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { - if let Some(no_mangle_attr) = cx - .sess() - .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) + if let Some(no_mangle_attr) = + attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) { check_no_mangle_on_generic_fn( no_mangle_attr, @@ -1306,7 +1304,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller // Now, check if the function has the `#[track_caller]` attribute - && let Some(attr) = cx.tcx.get_attr(def_id.to_def_id(), sym::track_caller) + && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { label: span, @@ -1601,7 +1599,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { // Ignore projections, as they can only be global // if the trait bound is global Clause(Clause::Projection(..)) | - AliasEq(..) | + AliasRelate(..) | // Ignore bounds that a user can't type WellFormed(..) | ObjectSafe(..) | @@ -1836,7 +1834,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { } let attrs = cx.tcx.hir().attrs(it.hir_id()); - if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { + if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) { cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems); } } @@ -2748,10 +2746,7 @@ impl ClashingExternDeclarations { // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. - ( - overridden_link_name, - tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span, - ) + (overridden_link_name, tcx.get_attr(fi.owner_id, sym::link_name).unwrap().span) }) { SymbolName::Link(overridden_link_name, overridden_link_name_span) @@ -2781,8 +2776,7 @@ impl ClashingExternDeclarations { // Given a transparent newtype, reach through and grab the inner // type unless the newtype makes the type non-null. - let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> { - let mut ty = ty; + let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> { loop { if let ty::Adt(def, substs) = *ty.kind() { let is_transparent = def.repr().transparent(); @@ -2792,14 +2786,14 @@ impl ClashingExternDeclarations { ty, is_transparent, is_non_null ); if is_transparent && !is_non_null { - debug_assert!(def.variants().len() == 1); - let v = &def.variant(VariantIdx::new(0)); - ty = transparent_newtype_field(tcx, v) - .expect( - "single-variant transparent structure with zero-sized field", - ) - .ty(tcx, substs); - continue; + debug_assert_eq!(def.variants().len(), 1); + let v = &def.variant(FIRST_VARIANT); + // continue with `ty`'s non-ZST field, + // otherwise `ty` is a ZST and we can return + if let Some(field) = transparent_newtype_field(tcx, v) { + ty = field.ty(tcx, substs); + continue; + } } } debug!("non_transparent_ty -> {:?}", ty); @@ -2813,10 +2807,8 @@ impl ClashingExternDeclarations { if !seen_types.insert((a, b)) { // We've encountered a cycle. There's no point going any further -- the types are // structurally the same. - return true; - } - let tcx = cx.tcx; - if a == b { + true + } else if a == b { // All nominally-same types are structurally same, too. true } else { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index f5a711315ea..626c09fea07 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -910,6 +910,10 @@ pub trait LintContext: Sized { Applicability::MachineApplicable, ); } + BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => { + db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace)); + db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace)); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 337a19dd024..65607d71805 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -224,8 +224,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast::ExprKind::Closure(box ast::Closure { asyncness: ast::Async::Yes { closure_id, .. }, .. - }) - | ast::ExprKind::Async(_, closure_id, ..) => self.check_id(closure_id), + }) => self.check_id(closure_id), _ => {} } } @@ -341,7 +340,7 @@ pub trait EarlyCheckNode<'a>: Copy { 'a: 'b; } -impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { +impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) { fn id(self) -> ast::NodeId { ast::CRATE_NODE_ID } @@ -349,15 +348,15 @@ impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { where 'a: 'b, { - &self.attrs + &self.1 } fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>) where 'a: 'b, { - lint_callback!(cx, check_crate, self); - ast_visit::walk_crate(cx, self); - lint_callback!(cx, check_crate_post, self); + lint_callback!(cx, check_crate, self.0); + ast_visit::walk_crate(cx, self.0); + lint_callback!(cx, check_crate_post, self.0); } } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index a3367ae4a9f..7b58bf03bbe 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; use rustc_middle::ty::{self, List}; use rustc_span::{sym, Span}; +use rustc_trait_selection::traits::ObligationCtxt; declare_lint! { /// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values. @@ -136,20 +137,22 @@ fn suggest_question_mark<'tcx>( let ty = substs.type_at(0); let infcx = cx.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); let cause = ObligationCause::new( span, body_def_id, rustc_infer::traits::ObligationCauseCode::MiscObligation, ); - let errors = rustc_trait_selection::traits::fully_solve_bound( - &infcx, + + ocx.register_bound( cause, - ty::ParamEnv::empty(), + cx.param_env, // Erase any region vids from the type, which may not be resolved infcx.tcx.erase_regions(ty), into_iterator_did, ); - errors.is_empty() + ocx.select_all_or_error().is_empty() } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index a14dc20fca3..9c7feadaf87 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -386,7 +386,7 @@ impl LateLintPass<'_> for Diagnostics { for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { if let Some(owner_did) = hir_id.as_owner() { found_parent_with_attr = found_parent_with_attr - || cx.tcx.has_attr(owner_did.to_def_id(), sym::rustc_lint_diagnostics); + || cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics); } debug!(?parent); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 20ab0af5856..8ec4c2b3d46 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1210,11 +1210,33 @@ impl<'a> DecorateLint<'a, ()> for DropGlue<'_> { #[diag(lint_range_endpoint_out_of_range)] pub struct RangeEndpointOutOfRange<'a> { pub ty: &'a str, - #[suggestion(code = "{start}..={literal}{suffix}", applicability = "machine-applicable")] - pub suggestion: Span, - pub start: String, - pub literal: u128, - pub suffix: &'a str, + #[subdiagnostic] + pub sub: UseInclusiveRange<'a>, +} + +#[derive(Subdiagnostic)] +pub enum UseInclusiveRange<'a> { + #[suggestion( + lint_range_use_inclusive_range, + code = "{start}..={literal}{suffix}", + applicability = "machine-applicable" + )] + WithoutParen { + #[primary_span] + sugg: Span, + start: String, + literal: u128, + suffix: &'a str, + }, + #[multipart_suggestion(lint_range_use_inclusive_range, applicability = "machine-applicable")] + WithParen { + #[suggestion_part(code = "=")] + eq_sugg: Span, + #[suggestion_part(code = "{literal}{suffix}")] + lit_sugg: Span, + literal: u128, + suffix: &'a str, + }, } #[derive(LintDiagnostic)] @@ -1390,7 +1412,7 @@ pub struct UnusedOp<'a> { pub op: &'a str, #[label] pub label: Span, - #[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")] + #[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")] pub suggestion: Span, } @@ -1434,17 +1456,15 @@ pub struct UnusedDef<'a, 'b> { } #[derive(Subdiagnostic)] -pub enum UnusedDefSuggestion { - #[suggestion( - lint_suggestion, - style = "verbose", - code = "let _ = ", - applicability = "machine-applicable" - )] - Default { - #[primary_span] - span: Span, - }, +#[suggestion( + lint_suggestion, + style = "verbose", + code = "let _ = ", + applicability = "maybe-incorrect" +)] +pub struct UnusedDefSuggestion { + #[primary_span] + pub span: Span, } // Needed because of def_path_str diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 62e8b4fe9e4..7c692fee333 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -56,6 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { return; } let arg_ty = cx.typeck_results().expr_ty(&args[0]); + let default_span = args[0].span; 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(); @@ -64,7 +65,10 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { MAP_UNIT_FN, span, MappingToUnit { - function_label: cx.tcx.span_of_impl(*id).unwrap(), + function_label: cx + .tcx + .span_of_impl(*id) + .unwrap_or(default_span), argument_label: args[0].span, map_label: arg_ty.default_span(cx.tcx), suggestion: path.ident.span, @@ -80,7 +84,10 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn { MAP_UNIT_FN, span, MappingToUnit { - function_label: cx.tcx.span_of_impl(*id).unwrap(), + function_label: cx + .tcx + .span_of_impl(*id) + .unwrap_or(default_span), argument_label: args[0].span, map_label: arg_ty.default_span(cx.tcx), suggestion: path.ident.span, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 71e2e66bdeb..9efc14849c7 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -328,8 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - cx.sess() - .find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) + attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { @@ -384,9 +383,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { match &fk { FnKind::Method(ident, sig, ..) => match method_context(cx, id) { MethodLateContext::PlainImpl => { - if sig.header.abi != Abi::Rust - && cx.tcx.has_attr(id.to_def_id(), sym::no_mangle) - { + if sig.header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { return; } self.check_snake_case(cx, "method", ident); @@ -398,7 +395,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.tcx.has_attr(id.to_def_id(), sym::no_mangle) { + if header.abi != Abi::Rust && cx.tcx.has_attr(id, sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); @@ -491,7 +488,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(it.hir_id()); match it.kind { - hir::ItemKind::Static(..) if !cx.sess().contains_name(attrs, sym::no_mangle) => { + hir::ItemKind::Static(..) if !attr::contains_name(attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); } hir::ItemKind::Const(..) => { diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 883a56cb3ce..f9d43fe2200 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -27,6 +27,8 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(type_alias_impl_trait)] + /// /// trait Duh {} /// /// impl Duh for i32 {} @@ -41,7 +43,9 @@ declare_lint! { /// type Assoc = F; /// } /// - /// fn test() -> impl Trait<Assoc = impl Sized> { + /// type Tait = impl Sized; + /// + /// fn test() -> impl Trait<Assoc = Tait> { /// 42 /// } /// ``` @@ -54,7 +58,7 @@ declare_lint! { /// /// Although the hidden type, `i32` does satisfy this bound, we do not /// consider the return type to be well-formed with this lint. It can be - /// fixed by changing `impl Sized` into `impl Sized + Send`. + /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`. pub OPAQUE_HIDDEN_INFERRED_BOUND, Warn, "detects the use of nested `impl Trait` types in associated type bounds that are not general enough" @@ -64,7 +68,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; }; + let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { return; }; let def_id = item.owner_id.def_id.to_def_id(); let infcx = &cx.tcx.infer_ctxt().build(); // For every projection predicate in the opaque type's explicit bounds, @@ -81,6 +85,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // have opaques in them anyways. let Some(proj_term) = proj.term.ty() else { continue }; + // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... + if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() + && cx.tcx.parent(opaque_ty.def_id) == def_id + && matches!( + opaque.origin, + hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) + ) + { + continue; + } + let proj_ty = cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs); // For every instance of the projection type in the bounds, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 7ca50f5a2db..f6bca7045c8 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -4,7 +4,8 @@ use crate::{ AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, - OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, VariantSizeDifferencesDiag, + OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange, + VariantSizeDifferencesDiag, }, }; use crate::{LateContext, LateLintPass, LintContext}; @@ -136,6 +137,14 @@ fn lint_overflowing_range_endpoint<'tcx>( expr: &'tcx hir::Expr<'tcx>, ty: &str, ) -> bool { + // Look past casts to support cases like `0..256 as u8` + let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.hir().get(cx.tcx.hir().parent_id(expr.hir_id)) + && let ExprKind::Cast(_, _) = par_expr.kind { + (par_expr, expr.span) + } else { + (expr, expr.span) + }; + // We only want to handle exclusive (`..`) ranges, // which are represented as `ExprKind::Struct`. let par_id = cx.tcx.hir().parent_id(expr.hir_id); @@ -155,7 +164,6 @@ fn lint_overflowing_range_endpoint<'tcx>( if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) { return false; }; - let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false }; use rustc_ast::{LitIntType, LitKind}; let suffix = match lit.node { @@ -164,16 +172,28 @@ fn lint_overflowing_range_endpoint<'tcx>( LitKind::Int(_, LitIntType::Unsuffixed) => "", _ => bug!(), }; - cx.emit_spanned_lint( - OVERFLOWING_LITERALS, - struct_expr.span, - RangeEndpointOutOfRange { - ty, - suggestion: struct_expr.span, + + let sub_sugg = if expr.span.lo() == lit_span.lo() { + let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false }; + UseInclusiveRange::WithoutParen { + sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), start, literal: lit_val - 1, suffix, - }, + } + } else { + UseInclusiveRange::WithParen { + eq_sugg: expr.span.shrink_to_lo(), + lit_sugg: lit_span, + literal: lit_val - 1, + suffix, + } + }; + + cx.emit_spanned_lint( + OVERFLOWING_LITERALS, + struct_expr.span, + RangeEndpointOutOfRange { ty, sub: sub_sugg }, ); // We've just emitted a lint, special cased for `(...)..MAX+1` ranges, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 2fab82d55cd..42e59f92840 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span); let type_lint_emitted_or_suppressed = match must_use_result { Some(path) => { - emit_must_use_untranslated(cx, &path, "", "", 1); + emit_must_use_untranslated(cx, &path, "", "", 1, false); true } None => false, @@ -258,11 +258,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned(), ) - .find_map(|obligation| { + .find_map(|(pred, _span)| { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Clause(ty::Clause::Trait( ref poly_trait_predicate, - )) = obligation.predicate.kind().skip_binder() + )) = pred.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; @@ -358,6 +358,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_pre_path, descr_post_path, 1, + false, ) }) .is_some() @@ -370,6 +371,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_pre: &str, descr_post: &str, plural_len: usize, + is_inner: bool, ) { let plural_suffix = pluralize!(plural_len); @@ -377,20 +379,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { MustUsePath::Suppressed => {} MustUsePath::Boxed(path) => { let descr_pre = &format!("{}boxed ", descr_pre); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); } MustUsePath::Opaque(path) => { let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); } MustUsePath::TraitObject(path) => { let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); } MustUsePath::TupleElement(elems) => { for (index, path) in elems { let descr_post = &format!(" in tuple element {}", index); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + emit_must_use_untranslated( + cx, path, descr_pre, descr_post, plural_len, true, + ); } } MustUsePath::Array(path, len) => { @@ -401,6 +405,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_pre, descr_post, plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)), + true, ); } MustUsePath::Closure(span) => { @@ -418,19 +423,6 @@ 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, @@ -440,7 +432,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx, def_id: *def_id, note: *reason, - suggestion, + suggestion: (!is_inner) + .then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }), }, ); } |
