diff options
Diffstat (limited to 'compiler/rustc_lint')
22 files changed, 615 insertions, 317 deletions
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 539eea3d8..fa1133e77 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -4,23 +4,25 @@ version = "0.0.0" edition = "2021" [dependencies] -tracing = "0.1" -unicode-security = "0.1.0" -rustc_middle = { path = "../rustc_middle" } +# tidy-alphabetical-start +rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } -rustc_errors = { path = "../rustc_errors" } -rustc_hir = { path = "../rustc_hir" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_target = { path = "../rustc_target" } -rustc_ast = { path = "../rustc_ast" } -rustc_span = { path = "../rustc_span" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } +rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_parse_format = { path = "../rustc_parse_format" } -rustc_infer = { path = "../rustc_infer" } rustc_type_ir = { path = "../rustc_type_ir" } -rustc_macros = { path = "../rustc_macros" } +tracing = "0.1" +unicode-security = "0.1.0" +# tidy-alphabetical-end diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7377c6e2f..068f1372c 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -5,6 +5,10 @@ lint_array_into_iter = .use_explicit_into_iter_suggestion = or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value +lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified + .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` + .suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change + lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` @@ -319,6 +323,8 @@ lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undef lint_invalid_reference_casting_note_book = for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> +lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get` + lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead @@ -488,6 +494,8 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}` lint_requested_level = requested on the command line with `{$level} {$lint_name}` +lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` + lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target .label = target type is set here @@ -543,19 +551,19 @@ lint_unused_closure = lint_unused_comparisons = comparison is useless due to type limits +lint_unused_coroutine = + unused {$pre}{$count -> + [one] coroutine + *[other] coroutine + }{$post} that must be used + .note = coroutines 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_unused_delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} -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_import_braces = braces around {$node} is unnecessary lint_unused_op = unused {$op} that must be used diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs new file mode 100644 index 000000000..512136473 --- /dev/null +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -0,0 +1,127 @@ +use crate::lints::AsyncFnInTraitDiag; +use crate::LateContext; +use crate::LateLintPass; +use rustc_hir as hir; +use rustc_trait_selection::traits::error_reporting::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait; + +declare_lint! { + /// The `async_fn_in_trait` lint detects use of `async fn` in the + /// definition of a publicly-reachable trait. + /// + /// ### Example + /// + /// ```rust + /// pub trait Trait { + /// async fn method(&self); + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When `async fn` is used in a trait definition, the trait does not + /// promise that the opaque [`Future`] returned by the associated function + /// or method will implement any [auto traits] such as [`Send`]. This may + /// be surprising and may make the associated functions or methods on the + /// trait less useful than intended. On traits exposed publicly from a + /// crate, this may affect downstream crates whose authors cannot alter + /// the trait definition. + /// + /// For example, this code is invalid: + /// + /// ```rust,compile_fail + /// pub trait Trait { + /// async fn method(&self) {} + /// } + /// + /// fn test<T: Trait>(x: T) { + /// fn spawn<T: Send>(_: T) {} + /// spawn(x.method()); // Not OK. + /// } + /// ``` + /// + /// This lint exists to warn authors of publicly-reachable traits that + /// they may want to consider desugaring the `async fn` to a normal `fn` + /// that returns an opaque `impl Future<..> + Send` type. + /// + /// For example, instead of: + /// + /// ```rust + /// pub trait Trait { + /// async fn method(&self) {} + /// } + /// ``` + /// + /// The author of the trait may want to write: + /// + /// + /// ```rust + /// use core::future::Future; + /// pub trait Trait { + /// fn method(&self) -> impl Future<Output = ()> + Send { async {} } + /// } + /// ``` + /// + /// This still allows the use of `async fn` within impls of the trait. + /// However, it also means that the trait will never be compatible with + /// impls where the returned [`Future`] of the method does not implement + /// `Send`. + /// + /// Conversely, if the trait is used only locally, if it is never used in + /// generic functions, or if it is only used in single-threaded contexts + /// that do not care whether the returned [`Future`] implements [`Send`], + /// then the lint may be suppressed. + /// + /// [`Future`]: https://doc.rust-lang.org/core/future/trait.Future.html + /// [`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html + /// [auto traits]: https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits + pub ASYNC_FN_IN_TRAIT, + Warn, + "use of `async fn` in definition of a publicly-reachable trait" +} + +declare_lint_pass!( + /// Lint for use of `async fn` in the definition of a publicly-reachable + /// trait. + AsyncFnInTrait => [ASYNC_FN_IN_TRAIT] +); + +impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) { + if let hir::TraitItemKind::Fn(sig, body) = item.kind + && let hir::IsAsync::Async(async_span) = sig.header.asyncness + { + // RTN can be used to bound `async fn` in traits in a better way than "always" + if cx.tcx.features().return_type_notation { + return; + } + + // Only need to think about library implications of reachable traits + if !cx.tcx.effective_visibilities(()).is_reachable(item.owner_id.def_id) { + return; + } + + let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) = + sig.decl.output + else { + // This should never happen, but let's not ICE. + return; + }; + let sugg = suggest_desugaring_async_fn_to_impl_future_in_trait( + cx.tcx, + sig, + body, + def.owner_id.def_id, + " + Send", + ); + cx.tcx.emit_spanned_lint( + ASYNC_FN_IN_TRAIT, + item.hir_id(), + async_span, + AsyncFnInTraitDiag { sugg }, + ); + } + } +} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 536f78a73..6f6150a41 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -121,16 +121,14 @@ impl EarlyLintPass for WhileTrue { { let condition_span = e.span.with_hi(cond.span.hi()); let replace = format!( - "{}loop", - label.map_or_else(String::new, |label| format!( - "{}: ", - label.ident, - )) - ); - cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue { - suggestion: condition_span, - replace, - }); + "{}loop", + label.map_or_else(String::new, |label| format!("{}: ", label.ident,)) + ); + cx.emit_spanned_lint( + WHILE_TRUE, + condition_span, + BuiltinWhileTrue { suggestion: condition_span, replace }, + ); } } } @@ -164,7 +162,9 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() + && leaf_ty.is_box() + { cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); } } @@ -677,11 +677,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) { return; } + if def.is_variant_list_non_exhaustive() + || def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive()) + { + return; + } // We shouldn't recommend implementing `Copy` on stateful things, // such as iterators. if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) - && cx.tcx + && cx + .tcx .infer_ctxt() .build() .type_implements_trait(iter_trait, [ty], param_env) @@ -1298,10 +1304,14 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { // Now, check if the function has the `#[track_caller]` attribute && 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, - parse_sess: &cx.tcx.sess.parse_sess, - }); + cx.emit_spanned_lint( + UNGATED_ASYNC_FN_TRACK_CALLER, + attr.span, + BuiltinUngatedAsyncFnTrackCaller { + label: span, + parse_sess: &cx.tcx.sess.parse_sess, + }, + ); } } } @@ -2244,7 +2254,7 @@ declare_lint! { } declare_lint_pass!( - /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`. + /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`. IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES] ); @@ -2258,23 +2268,19 @@ impl EarlyLintPass for IncompleteInternalFeatures { .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) .filter(|(&name, _)| features.incomplete(name) || features.internal(name)) .for_each(|(&name, &span)| { - let note = rustc_feature::find_feature_issue(name, GateIssue::Language) - .map(|n| BuiltinFeatureIssueNote { n }); - if features.incomplete(name) { + let note = rustc_feature::find_feature_issue(name, GateIssue::Language) + .map(|n| BuiltinFeatureIssueNote { n }); let help = HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp); + cx.emit_spanned_lint( INCOMPLETE_FEATURES, span, BuiltinIncompleteFeatures { name, note, help }, ); } else { - cx.emit_spanned_lint( - INTERNAL_FEATURES, - span, - BuiltinInternalFeatures { name, note }, - ); + cx.emit_spanned_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name }); } }); } @@ -2469,7 +2475,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { ty: Ty<'tcx>, init: InitKind, ) -> Option<InitError> { - use rustc_type_ir::sty::TyKind::*; + use rustc_type_ir::TyKind::*; match ty.kind() { // Primitive types that don't like 0 as a value. Ref(..) => Some("references must be non-null".into()), diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 3c5cde430..a5f4c5ff0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -31,7 +31,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError}; use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, TyCtxt}; use rustc_session::config::ExpectedValues; use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; @@ -109,7 +109,7 @@ struct LintAlias { struct LintGroup { lint_ids: Vec<LintId>, - from_plugin: bool, + is_loaded: bool, depr: Option<LintAlias>, } @@ -160,9 +160,7 @@ impl LintStore { // Don't display deprecated lint groups. depr.is_none() }) - .map(|(k, LintGroup { lint_ids, from_plugin, .. })| { - (*k, lint_ids.clone(), *from_plugin) - }) + .map(|(k, LintGroup { lint_ids, is_loaded, .. })| (*k, lint_ids.clone(), *is_loaded)) } pub fn register_early_pass( @@ -221,7 +219,7 @@ impl LintStore { .entry(edition.lint_name()) .or_insert(LintGroup { lint_ids: vec![], - from_plugin: lint.is_plugin, + is_loaded: lint.is_loaded, depr: None, }) .lint_ids @@ -234,7 +232,7 @@ impl LintStore { .entry("future_incompatible") .or_insert(LintGroup { lint_ids: vec![], - from_plugin: lint.is_plugin, + is_loaded: lint.is_loaded, depr: None, }) .lint_ids @@ -249,7 +247,7 @@ impl LintStore { alias, LintGroup { lint_ids: vec![], - from_plugin: false, + is_loaded: false, depr: Some(LintAlias { name: lint_name, silent: true }), }, ); @@ -257,21 +255,21 @@ impl LintStore { pub fn register_group( &mut self, - from_plugin: bool, + is_loaded: bool, name: &'static str, deprecated_name: Option<&'static str>, to: Vec<LintId>, ) { let new = self .lint_groups - .insert(name, LintGroup { lint_ids: to, from_plugin, depr: None }) + .insert(name, LintGroup { lint_ids: to, is_loaded, depr: None }) .is_none(); if let Some(deprecated) = deprecated_name { self.lint_groups.insert( deprecated, LintGroup { lint_ids: vec![], - from_plugin, + is_loaded, depr: Some(LintAlias { name, silent: false }), }, ); @@ -727,11 +725,14 @@ pub trait LintContext: Sized { .collect::<Vec<_>>(); possibilities.sort(); + let mut should_print_possibilities = true; if let Some((value, value_span)) = value { if best_match_values.contains(&Some(value)) { db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect); + should_print_possibilities = false; } else if best_match_values.contains(&None) { db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect); + should_print_possibilities = false; } else if let Some(first_value) = possibilities.first() { db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect); } else { @@ -741,13 +742,25 @@ pub trait LintContext: Sized { db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); } - if !possibilities.is_empty() { + if !possibilities.is_empty() && should_print_possibilities { let possibilities = possibilities.join("`, `"); db.help(format!("expected values for `{best_match}` are: `{possibilities}`")); } } else { db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); } + } else if !possibilities.is_empty() { + let mut possibilities = possibilities.iter() + .map(Symbol::as_str) + .collect::<Vec<_>>(); + possibilities.sort(); + let possibilities = possibilities.join("`, `"); + + // The list of expected names can be long (even by default) and + // so the diagnostic produced can take a lot of space. To avoid + // cloging the user output we only want to print that diagnostic + // once. + db.help_once(format!("expected names are: `{possibilities}`")); } }, BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => { @@ -1185,51 +1198,45 @@ impl<'tcx> LateContext<'tcx> { /// } /// ``` pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> { - pub struct AbsolutePathPrinter<'tcx> { - pub tcx: TyCtxt<'tcx>, + struct AbsolutePathPrinter<'tcx> { + tcx: TyCtxt<'tcx>, + path: Vec<Symbol>, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { - type Error = !; - - type Path = Vec<Symbol>; - type Region = (); - type Type = (); - type DynExistential = (); - type Const = (); - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { + fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { Ok(()) } - fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { + fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> { Ok(()) } fn print_dyn_existential( - self, + &mut self, _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { + ) -> Result<(), PrintError> { Ok(()) } - fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> { Ok(()) } - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - Ok(vec![self.tcx.crate_name(cnum)]) + fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { + self.path = vec![self.tcx.crate_name(cnum)]; + Ok(()) } fn path_qualified( - self, + &mut self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<(), PrintError> { if trait_ref.is_none() { if let ty::Adt(def, args) = self_ty.kind() { return self.print_def_path(def.did(), args); @@ -1238,24 +1245,25 @@ impl<'tcx> LateContext<'tcx> { // This shouldn't ever be needed, but just in case: with_no_trimmed_paths!({ - Ok(vec![match trait_ref { + self.path = vec![match trait_ref { Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")), None => Symbol::intern(&format!("<{self_ty}>")), - }]) + }]; + Ok(()) }) } fn path_append_impl( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + &mut self, + print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - let mut path = print_prefix(self)?; + ) -> Result<(), PrintError> { + print_prefix(self)?; // This shouldn't ever be needed, but just in case: - path.push(match trait_ref { + self.path.push(match trait_ref { Some(trait_ref) => { with_no_trimmed_paths!(Symbol::intern(&format!( "<impl {} for {}>", @@ -1268,35 +1276,37 @@ impl<'tcx> LateContext<'tcx> { } }); - Ok(path) + Ok(()) } fn path_append( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + &mut self, + print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { - let mut path = print_prefix(self)?; + ) -> Result<(), PrintError> { + print_prefix(self)?; // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs. if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data { - return Ok(path); + return Ok(()); } - path.push(Symbol::intern(&disambiguated_data.data.to_string())); - Ok(path) + self.path.push(Symbol::intern(&disambiguated_data.data.to_string())); + Ok(()) } fn path_generic_args( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + &mut self, + print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, _args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<(), PrintError> { print_prefix(self) } } - AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap() + let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] }; + printer.print_def_path(def_id, &[]).unwrap(); + printer.path } /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`. @@ -1342,7 +1352,7 @@ impl<'tcx> LateContext<'tcx> { && let Some(init) = match parent_node { hir::Node::Expr(expr) => Some(expr), hir::Node::Local(hir::Local { init, .. }) => *init, - _ => None + _ => None, } { expr = init.peel_blocks(); @@ -1391,9 +1401,9 @@ impl<'tcx> LateContext<'tcx> { hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { Some(self.tcx.hir().body(body_id).value) } - _ => None - } - _ => None + _ => None, + }, + _ => None, } { expr = init.peel_blocks(); diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 9be2edf84..d2d99bc0d 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -4,9 +4,10 @@ use crate::{ }; use rustc_hir as hir; -use rustc_middle::{traits::util::supertraits, ty}; +use rustc_middle::ty; use rustc_session::lint::FutureIncompatibilityReason; use rustc_span::sym; +use rustc_trait_selection::traits::supertraits; declare_lint! { /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the @@ -75,14 +76,16 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)) .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal) { - let label = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)).map(|label| SupertraitAsDerefTargetLabel { - label, - }); - cx.emit_spanned_lint(DEREF_INTO_DYN_SUPERTRAIT, cx.tcx.def_span(item.owner_id.def_id), SupertraitAsDerefTarget { - t, - target_principal, - label, - }); + let label = impl_ + .items + .iter() + .find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) + .map(|label| SupertraitAsDerefTargetLabel { label }); + cx.emit_spanned_lint( + DEREF_INTO_DYN_SUPERTRAIT, + cx.tcx.def_span(item.owner_id.def_id), + SupertraitAsDerefTarget { t, target_principal, label }, + ); } } } diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 467f53d44..390a1620a 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -149,18 +149,37 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); match fn_name { sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span }); - }, + cx.emit_spanned_lint( + DROPPING_REFERENCES, + expr.span, + DropRefDiag { arg_ty, label: arg.span }, + ); + } sym::mem_forget if arg_ty.is_ref() => { - cx.emit_spanned_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span }); - }, + cx.emit_spanned_lint( + FORGETTING_REFERENCES, + expr.span, + ForgetRefDiag { arg_ty, label: arg.span }, + ); + } sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint( + DROPPING_COPY_TYPES, + expr.span, + DropCopyDiag { arg_ty, label: arg.span }, + ); } sym::mem_forget if is_copy => { - cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint( + FORGETTING_COPY_TYPES, + expr.span, + ForgetCopyDiag { arg_ty, label: arg.span }, + ); } - sym::mem_drop if let ty::Adt(adt, _) = arg_ty.kind() && adt.is_manually_drop() => { + sym::mem_drop + if let ty::Adt(adt, _) = arg_ty.kind() + && adt.is_manually_drop() => + { cx.emit_spanned_lint( UNDROPPED_MANUALLY_DROPS, expr.span, @@ -169,9 +188,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { label: arg.span, suggestion: UndroppedManuallyDropsSuggestion { start_span: arg.span.shrink_to_lo(), - end_span: arg.span.shrink_to_hi() - } - } + end_span: arg.span.shrink_to_hi(), + }, + }, ); } _ => return, diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index b1266b58a..740c90757 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -11,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) { } fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { - if !tcx.features().enabled(sym::lint_reasons) { + if !tcx.features().active(sym::lint_reasons) { return; } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index c299e3884..c8ec0458b 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -59,13 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { _ => return, }; - let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) + let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span) - { - ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip } - } else { - ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var } - } ; + { + ForLoopsOverFalliblesLoopSub::RemoveNext { + suggestion: recv.span.between(arg.span.shrink_to_hi()), + recv_snip, + } + } else { + ForLoopsOverFalliblesLoopSub::UseWhileLet { + start_span: expr.span.with_hi(pat.span.lo()), + end_span: pat.span.between(arg.span), + var, + } + }; let question_mark = suggest_question_mark(cx, adt, args, expr.span) .then(|| ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() }); let suggestion = ForLoopsOverFalliblesSuggestion { @@ -84,13 +91,13 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>)> { if let hir::ExprKind::DropTemps(e) = expr.kind - && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind - && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind - && let hir::ExprKind::Loop(block, ..) = arm.body.kind - && let [stmt] = block.stmts - && let hir::StmtKind::Expr(e) = stmt.kind - && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind - && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind + && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind + && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind + && let hir::ExprKind::Loop(block, ..) = arm.body.kind + && let [stmt] = block.stmts + && let hir::StmtKind::Expr(e) = stmt.kind + && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind + && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind { Some((field.pat, arg)) } else { @@ -104,11 +111,11 @@ fn extract_iterator_next_call<'tcx>( ) -> Option<&'tcx Expr<'tcx>> { // This won't work for `Iterator::next(iter)`, is this an issue? if let hir::ExprKind::MethodCall(_, recv, _, _) = expr.kind - && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn() + && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn() { Some(recv) } else { - return None + return None; } } diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index e1df69bda..86b3b4ad0 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -262,7 +262,7 @@ fn structurally_same_type_impl<'tcx>( true } else { // Do a full, depth-first comparison between the two. - use rustc_type_ir::sty::TyKind::*; + use rustc_type_ir::TyKind::*; let a_kind = a.kind(); let b_kind = b.kind(); @@ -369,8 +369,8 @@ fn structurally_same_type_impl<'tcx>( (Dynamic(..), Dynamic(..)) | (Error(..), Error(..)) | (Closure(..), Closure(..)) - | (Generator(..), Generator(..)) - | (GeneratorWitness(..), GeneratorWitness(..)) + | (Coroutine(..), Coroutine(..)) + | (CoroutineWitness(..), CoroutineWitness(..)) | (Alias(ty::Projection, ..), Alias(ty::Projection, ..)) | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..)) | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 4b803621f..2d86129c4 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -3,14 +3,14 @@ use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword, - QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, + QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, UntranslatableDiagnosticTrivial, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_hir::def::Res; use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; -use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; +use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -62,13 +62,11 @@ fn typeck_results_of_method_fn<'tcx>( if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { Some((segment.ident.span, def_id, cx.typeck_results().node_args(expr.hir_id))) - }, - _ => { - match cx.typeck_results().node_type(expr.hir_id).kind() { - &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)), - _ => None, - } } + _ => match cx.typeck_results().node_type(expr.hir_id).kind() { + &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)), + _ => None, + }, } } @@ -134,14 +132,11 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { _: rustc_hir::HirId, ) { if let Some(segment) = path.segments.iter().nth_back(1) - && lint_ty_kind_usage(cx, &segment.res) + && lint_ty_kind_usage(cx, &segment.res) { - let span = path.span.with_hi( - segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() - ); - cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { - suggestion: span, - }); + let span = + path.span.with_hi(segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()); + cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span }); } } @@ -166,10 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { None } } - Some(Node::Expr(Expr { - kind: ExprKind::Path(qpath), - .. - })) => { + Some(Node::Expr(Expr { kind: ExprKind::Path(qpath), .. })) => { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { @@ -180,10 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } // Can't unify these two branches because qpath below is `&&` and above is `&` // and `A | B` paths don't play well together with adjustments, apparently. - Some(Node::Expr(Expr { - kind: ExprKind::Struct(qpath, ..), - .. - })) => { + Some(Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. })) => { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { @@ -192,22 +181,28 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { None } } - _ => None + _ => None, }; match span { Some(span) => { - cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { - suggestion: span, - }); - }, + cx.emit_spanned_lint( + USAGE_OF_TY_TYKIND, + path.span, + TykindKind { suggestion: span }, + ); + } None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag), } - } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) { - cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified { - ty, - suggestion: path.span, - }); + } else if !ty.span.from_expansion() + && path.segments.len() > 1 + && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) + { + cx.emit_spanned_lint( + USAGE_OF_QUALIFIED_TY, + path.span, + TyQualified { ty, suggestion: path.span }, + ); } } _ => {} @@ -398,11 +393,11 @@ impl LateLintPass<'_> for Diagnostics { } debug!(?parent); - if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent && - let Impl { of_trait: Some(of_trait), .. } = impl_ && - let Some(def_id) = of_trait.trait_def_id() && - let Some(name) = cx.tcx.get_diagnostic_name(def_id) && - matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint) + if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent + && let Impl { of_trait: Some(of_trait), .. } = impl_ + && let Some(def_id) = of_trait.trait_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(def_id) + && matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint) { found_impl = true; break; @@ -416,9 +411,9 @@ impl LateLintPass<'_> for Diagnostics { let mut found_diagnostic_message = false; for ty in args.types() { debug!(?ty); - if let Some(adt_def) = ty.ty_adt_def() && - let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) && - matches!(name, sym::DiagnosticMessage | sym::SubdiagnosticMessage) + if let Some(adt_def) = ty.ty_adt_def() + && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) + && matches!(name, sym::DiagnosticMessage | sym::SubdiagnosticMessage) { found_diagnostic_message = true; break; @@ -486,8 +481,9 @@ impl EarlyLintPass for Diagnostics { } }; if let ast::ExprKind::Lit(lit) = arg.kind - && let ast::token::LitKind::Str = lit.kind { - true + && let ast::token::LitKind::Str = lit.kind + { + true } else { false } @@ -524,17 +520,50 @@ impl LateLintPass<'_> for BadOptAccess { } for field in adt_def.all_fields() { - if field.name == target.name && - let Some(attr) = cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) && - let Some(items) = attr.meta_item_list() && - let Some(item) = items.first() && - let Some(lit) = item.lit() && - let ast::LitKind::Str(val, _) = lit.kind + if field.name == target.name + && let Some(attr) = + cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) + && let Some(items) = attr.meta_item_list() + && let Some(item) = items.first() + && let Some(lit) = item.lit() + && let ast::LitKind::Str(val, _) = lit.kind { - cx.emit_spanned_lint(BAD_OPT_ACCESS, expr.span, BadOptAccessDiag { - msg: val.as_str(), - }); + cx.emit_spanned_lint( + BAD_OPT_ACCESS, + expr.span, + BadOptAccessDiag { msg: val.as_str() }, + ); } } } } + +declare_tool_lint! { + pub rustc::SPAN_USE_EQ_CTXT, + Allow, + "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead", + report_in_external_macro: true +} + +declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]); + +impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind { + if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) { + cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag); + } + } + } +} + +fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match &expr.kind { + ExprKind::MethodCall(..) => cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)), + + _ => false, + } +} diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index e398059ad..0b91b77a9 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -64,8 +64,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) - && [sym::str_from_utf8, sym::str_from_utf8_mut, - sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + && [ + sym::str_from_utf8, + sym::str_from_utf8_mut, + sym::str_from_utf8_unchecked, + sym::str_from_utf8_unchecked_mut, + ] + .contains(&diag_item) { let lint = |label, utf8_error: Utf8Error| { let method = diag_item.as_str().strip_prefix("str_").unwrap(); @@ -74,13 +79,17 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { let is_unchecked_variant = diag_item.as_str().contains("unchecked"); cx.emit_spanned_lint( - if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, + if is_unchecked_variant { + INVALID_FROM_UTF8_UNCHECKED + } else { + INVALID_FROM_UTF8 + }, expr.span, if is_unchecked_variant { InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } } else { InvalidFromUtf8Diag::Checked { method, valid_up_to, label } - } + }, ) }; @@ -95,18 +104,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { { lint(init.span, utf8_error); } - }, + } ExprKind::Array(args) => { - let elements = args.iter().map(|e|{ - match &e.kind { + let elements = args + .iter() + .map(|e| match &e.kind { ExprKind::Lit(Spanned { node: lit, .. }) => match lit { LitKind::Byte(b) => Some(*b), LitKind::Int(b, _) => Some(*b as u8), - _ => None - } - _ => None - } - }).collect::<Option<Vec<_>>>(); + _ => None, + }, + _ => None, + }) + .collect::<Option<Vec<_>>>(); if let Some(elements) = elements && let Err(utf8_error) = std::str::from_utf8(&elements) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index ba521b969..0d20f6232 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -634,7 +634,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { /// diagnostic with no change to `specs`. fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) { let (old_level, old_src) = self.provider.get_lint_level(id.lint, &self.sess); - if let Level::Expect(id) = &mut level && let LintExpectationId::Stable { .. } = id { + if let Level::Expect(id) = &mut level + && let LintExpectationId::Stable { .. } = id + { *id = id.normalize(); } // Setting to a non-forbid level is an error if the lint previously had @@ -706,7 +708,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { // The lint `unfulfilled_lint_expectations` can't be expected, as it would suppress itself. // Handling expectations of this lint would add additional complexity with little to no // benefit. The expect level for this lint will therefore be ignored. - if let Level::Expect(_) = level && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS) { + if let Level::Expect(_) = level + && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS) + { return; } @@ -747,8 +751,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { None => continue, // This is the only lint level with a `LintExpectationId` that can be created from an attribute Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { - let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id - else { bug!("stable id Level::from_attr") }; + let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id else { + bug!("stable id Level::from_attr") + }; let stable_id = LintExpectationId::Stable { hir_id, @@ -1057,7 +1062,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { #[track_caller] fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool { if let Some(feature) = lint_id.lint.feature_gate { - if !self.features.enabled(feature) { + if !self.features.active(feature) { let lint = builtin::UNKNOWN_LINTS; let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS); struct_lint_level( diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 72c103f2d..54adedd3c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -10,7 +10,7 @@ //! all other analyses. The `LintPass`es built into rustc are defined //! within [rustc_session::lint::builtin], //! which has further comments on how to add such a lint. -//! rustc can also load user-defined lint plugins via the plugin mechanism. +//! rustc can also load external lint plugins, as is done for Clippy. //! //! Some of rustc's lints are defined elsewhere in the compiler and work by //! calling `add_lint()` on the overall `Session` object. This works when @@ -27,6 +27,8 @@ #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(array_windows)] #![feature(box_patterns)] #![feature(control_flow_enum)] @@ -50,6 +52,7 @@ extern crate rustc_session; extern crate tracing; mod array_into_iter; +mod async_fn_in_trait; pub mod builtin; mod context; mod deref_into_dyn_supertrait; @@ -96,6 +99,7 @@ use rustc_session::lint::builtin::{ }; use array_into_iter::ArrayIntoIter; +use async_fn_in_trait::AsyncFnInTrait; use builtin::*; use deref_into_dyn_supertrait::*; use drop_forget_useless::*; @@ -234,6 +238,7 @@ late_lint_methods!( MapUnitFn: MapUnitFn, MissingDebugImplementations: MissingDebugImplementations, MissingDoc: MissingDoc, + AsyncFnInTrait: AsyncFnInTrait, ] ] ); @@ -501,6 +506,11 @@ fn register_builtins(store: &mut LintStore) { "replaced with another group of lints, see RFC \ <https://rust-lang.github.io/rfcs/2145-type-privacy.html> for more information", ); + store.register_removed( + "invalid_alignment", + "converted into hard error, see PR #104616 \ + <https://github.com/rust-lang/rust/pull/104616> for more information", + ); } fn register_internals(store: &mut LintStore) { @@ -521,6 +531,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_mod_pass(|_| Box::new(BadOptAccess)); store.register_lints(&PassByValue::get_lints()); store.register_late_mod_pass(|_| Box::new(PassByValue)); + store.register_lints(&SpanUseEqCtxt::get_lints()); + store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and // these lints will trigger all of the time - change this once migration to diagnostic structs @@ -538,6 +550,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(EXISTING_DOC_KEYWORD), LintId::of(BAD_OPT_ACCESS), + LintId::of(SPAN_USE_EQ_CTXT), ], ); } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c091c260a..756899e50 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -412,8 +412,6 @@ pub struct BuiltinIncompleteFeatures { #[note] pub struct BuiltinInternalFeatures { pub name: Symbol, - #[subdiagnostic] - pub note: Option<BuiltinFeatureIssueNote>, } #[derive(Subdiagnostic)] @@ -771,12 +769,16 @@ pub enum InvalidReferenceCastingDiag { BorrowAsMut { #[label] orig_cast: Option<Span>, + #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)] + ty_has_interior_mutability: Option<()>, }, #[diag(lint_invalid_reference_casting_assign_to_ref)] #[note(lint_invalid_reference_casting_note_book)] AssignToRef { #[label] orig_cast: Option<Span>, + #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)] + ty_has_interior_mutability: Option<()>, }, } @@ -899,6 +901,10 @@ pub struct QueryInstability { } #[derive(LintDiagnostic)] +#[diag(lint_span_use_eq_ctxt)] +pub struct SpanUseEqCtxtDiag; + +#[derive(LintDiagnostic)] #[diag(lint_tykind_kind)] pub struct TykindKind { #[suggestion(code = "ty", applicability = "maybe-incorrect")] @@ -1694,9 +1700,9 @@ pub struct UnusedClosure<'a> { // FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings #[derive(LintDiagnostic)] -#[diag(lint_unused_generator)] +#[diag(lint_unused_coroutine)] #[note] -pub struct UnusedGenerator<'a> { +pub struct UnusedCoroutine<'a> { pub count: usize, pub pre: &'a str, pub post: &'a str, @@ -1818,3 +1824,24 @@ pub struct UnusedAllocationDiag; #[derive(LintDiagnostic)] #[diag(lint_unused_allocation_mut)] pub struct UnusedAllocationMutDiag; + +pub struct AsyncFnInTraitDiag { + pub sugg: Option<Vec<(Span, String)>>, +} + +impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.note(fluent::lint_note); + if let Some(sugg) = self.sugg { + diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect); + } + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + fluent::lint_async_fn_in_trait + } +} diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 84558ee1f..dfefaf82f 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -42,18 +42,17 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { 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.as_trait_clause()); + let direct_super_traits_iter = cx + .tcx + .super_predicates_of(def_id) + .predicates + .into_iter() + .filter_map(|(pred, _)| pred.as_trait_clause()); 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 - }, + crate::lints::MultipleSupertraitUpcastable { ident: item.ident }, ); } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 145de4948..66dc726df 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -511,7 +511,9 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) { + if let hir::ImplItemKind::Const(..) = ii.kind + && !assoc_item_in_trait_impl(cx, ii) + { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); } } diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 79b0b32be..c24846ca9 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -37,8 +37,6 @@ declare_lint! { /// type Assoc: Duh; /// } /// - /// struct Struct; - /// /// impl<F: Duh> Trait for F { /// type Assoc = F; /// } @@ -53,12 +51,12 @@ declare_lint! { /// {{produces}} /// /// In this example, `test` declares that the associated type `Assoc` for - /// `impl Trait` is `impl Sized`, which does not satisfy the `Send` bound + /// `impl Trait` is `impl Sized`, which does not satisfy the bound `Duh` /// on the associated type. /// /// 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 `Tait = impl Sized` into `Tait = impl Sized + Send`. + /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Duh`. pub OPAQUE_HIDDEN_INFERRED_BOUND, Warn, "detects the use of nested `impl Trait` types in associated type bounds that are not general enough" @@ -79,9 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() { - // Liberate bound regions in the predicate since we - // don't actually care about lifetimes in this check. - let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind()); + let predicate = infcx.instantiate_binder_with_placeholders(pred.kind()); let ty::ClauseKind::Projection(proj) = predicate else { continue; }; diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 0de72d8d3..4ac8a5ceb 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -46,22 +46,26 @@ fn incorrect_check<'a, 'tcx: 'a>( if let ExprKind::MethodCall(_, _expr, [], _) = e.kind && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) - && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { + && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) + { return Some(PtrNullChecksDiag::FnRet { fn_name }); } else if let ExprKind::Call(path, _args) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) - && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { + && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) + { return Some(PtrNullChecksDiag::FnRet { fn_name }); } e = if let ExprKind::Cast(expr, t) = e.kind - && let TyKind::Ptr(_) = t.kind { + && let TyKind::Ptr(_) = t.kind + { had_at_least_one_cast = true; expr } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) - && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) { + && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) + { had_at_least_one_cast = true; expr } else if had_at_least_one_cast { @@ -127,10 +131,11 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>) ExprKind::Cast(cast_expr, _) if let ExprKind::Lit(spanned) = cast_expr.kind - && let LitKind::Int(v, _) = spanned.node && v == 0 => + && let LitKind::Int(v, _) = spanned.node + && v == 0 => { cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) - }, + } // Catching: // (fn_ptr as *<const/mut> <ty>) == std::ptr::null() @@ -141,9 +146,9 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) => { cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) - }, + } - _ => {}, + _ => {} } } _ => {} diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 39def599b..d44691b5e 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -43,19 +43,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { let init = cx.expr_or_init(e); - let orig_cast = if is_cast_from_const_to_mut(cx, init) { - if init.span != e.span { Some(init.span) } else { None } - } else { + let Some(ty_has_interior_mutability) = is_cast_from_const_to_mut(cx, init) else { return; }; + let orig_cast = if init.span != e.span { Some(init.span) } else { None }; + let ty_has_interior_mutability = ty_has_interior_mutability.then_some(()); cx.emit_spanned_lint( INVALID_REFERENCE_CASTING, expr.span, if is_assignment { - InvalidReferenceCastingDiag::AssignToRef { orig_cast } + InvalidReferenceCastingDiag::AssignToRef { orig_cast, ty_has_interior_mutability } } else { - InvalidReferenceCastingDiag::BorrowAsMut { orig_cast } + InvalidReferenceCastingDiag::BorrowAsMut { orig_cast, ty_has_interior_mutability } }, ); } @@ -93,7 +93,10 @@ fn is_operation_we_care_about<'tcx>( if let ExprKind::Call(path, [arg_ptr, _arg_val]) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned)) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned) + ) { Some((true, arg_ptr)) } else { @@ -104,7 +107,10 @@ fn is_operation_we_care_about<'tcx>( deref_assign_or_addr_of(e).or_else(|| ptr_write(cx, e)) } -fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr<'tcx>) -> bool { +fn is_cast_from_const_to_mut<'tcx>( + cx: &LateContext<'tcx>, + orig_expr: &'tcx Expr<'tcx>, +) -> Option<bool> { let mut need_check_freeze = false; let mut e = orig_expr; @@ -112,7 +118,7 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr // Bail out early if the end type is **not** a mutable pointer. if !matches!(end_ty.kind(), ty::RawPtr(TypeAndMut { ty: _, mutbl: Mutability::Mut })) { - return false; + return None; } loop { @@ -155,10 +161,11 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr // // We also consider non concrete skeleton types (ie generics) // to be an issue since there is no way to make it safe for abitrary types. - !need_check_freeze - || inner_ty.is_freeze(cx.tcx, cx.param_env) - || !inner_ty.has_concrete_skeleton() + let inner_ty_has_interior_mutability = + !inner_ty.is_freeze(cx.tcx, cx.param_env) && inner_ty.has_concrete_skeleton(); + (!need_check_freeze || !inner_ty_has_interior_mutability) + .then_some(inner_ty_has_interior_mutability) } else { - false + None } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 44cf1591c..c04053d18 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -140,13 +140,15 @@ declare_lint! { pub struct TypeLimits { /// Id of the last visited negated expression negated_expr_id: Option<hir::HirId>, + /// Span of the last visited negated expression + negated_expr_span: Option<Span>, } impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS, INVALID_NAN_COMPARISONS]); impl TypeLimits { pub fn new() -> TypeLimits { - TypeLimits { negated_expr_id: None } + TypeLimits { negated_expr_id: None, negated_expr_span: None } } } @@ -161,8 +163,10 @@ fn lint_overflowing_range_endpoint<'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 { + 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) @@ -426,17 +430,15 @@ fn lint_int_literal<'tcx>( return; } - let lit = cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"); + let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span }; + let lit = + cx.sess().source_map().span_to_snippet(span).expect("must get snippet from literal"); let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); cx.emit_spanned_lint( OVERFLOWING_LITERALS, - e.span, + span, OverflowingInt { ty: t.name_str(), lit, min, max, help }, ); } @@ -580,8 +582,8 @@ fn lint_nan<'tcx>( ) -> InvalidNanComparisons { // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const. let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| { - if let Some(l_span) = l.span.find_ancestor_inside(e.span) && - let Some(r_span) = r.span.find_ancestor_inside(e.span) + if let Some(l_span) = l.span.find_ancestor_inside(e.span) + && let Some(r_span) = r.span.find_ancestor_inside(e.span) { f(l_span, r_span) } else { @@ -622,9 +624,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { match e.kind { hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { - // propagate negation, if the negation itself isn't negated + // Propagate negation, if the negation itself isn't negated if self.negated_expr_id != Some(e.hir_id) { self.negated_expr_id = Some(expr.hir_id); + self.negated_expr_span = Some(e.span); } } hir::ExprKind::Binary(binop, ref l, ref r) => { @@ -1269,8 +1272,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ty::Bound(..) | ty::Error(_) | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) | ty::Placeholder(..) | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), } @@ -1292,11 +1295,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { CItemKind::Definition => "fn", }; let span_note = if let ty::Adt(def, _) = ty.kind() - && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { - Some(sp) - } else { - None - }; + && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) + { + Some(sp) + } else { + None + }; self.cx.emit_spanned_lint( lint, sp, @@ -1459,7 +1463,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) { + if let ty::FnPtr(sig) = ty.kind() + && !self.visitor.is_internal_abi(sig.abi()) + { self.tys.push(ty); } @@ -1733,7 +1739,8 @@ impl InvalidAtomicOrdering { } fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) + if let Some((method, args)) = + Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) && let Some((ordering_arg, invalid_ordering)) = match method { sym::load => Some((&args[0], sym::Release)), sym::store => Some((&args[1], sym::Acquire)), @@ -1743,9 +1750,17 @@ impl InvalidAtomicOrdering { && (ordering == invalid_ordering || ordering == sym::AcqRel) { if method == sym::load { - cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingLoad); + cx.emit_spanned_lint( + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + AtomicOrderingLoad, + ); } else { - cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingStore); + cx.emit_spanned_lint( + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + AtomicOrderingStore, + ); }; } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index d5beff4f1..355855b8e 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, UnusedDefSuggestion, UnusedDelim, - UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion, + UnusedAllocationMutDiag, UnusedClosure, UnusedCoroutine, UnusedDef, UnusedDefSuggestion, + UnusedDelim, UnusedDelimSuggestion, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion, UnusedResult, }; use crate::Lint; @@ -257,8 +257,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { Array(Box<Self>, u64), /// The root of the unused_closures lint. Closure(Span), - /// The root of the unused_generators lint. - Generator(Span), + /// The root of the unused_coroutines lint. + Coroutine(Span), } #[instrument(skip(cx, expr), level = "debug", ret)] @@ -350,16 +350,16 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .map(|inner| MustUsePath::Array(Box::new(inner), len)), }, ty::Closure(..) => Some(MustUsePath::Closure(span)), - ty::Generator(def_id, ..) => { + ty::Coroutine(def_id, ..) => { // async fn should be treated as "implementor of `Future`" - let must_use = if cx.tcx.generator_is_async(def_id) { - let def_id = cx.tcx.lang_items().future_trait().unwrap(); + let must_use = if cx.tcx.coroutine_is_async(def_id) { + let def_id = cx.tcx.lang_items().future_trait()?; is_def_must_use(cx, def_id, span) .map(|inner| MustUsePath::Opaque(Box::new(inner))) } else { None }; - must_use.or(Some(MustUsePath::Generator(span))) + must_use.or(Some(MustUsePath::Coroutine(span))) } _ => None, } @@ -482,11 +482,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post }, ); } - MustUsePath::Generator(span) => { + MustUsePath::Coroutine(span) => { cx.emit_spanned_lint( UNUSED_MUST_USE, *span, - UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post }, + UnusedCoroutine { count: plural_len, pre: descr_pre, post: descr_post }, ); } MustUsePath::Def(span, def_id, reason) => { @@ -782,21 +782,23 @@ trait UnusedDelimLint { }; let suggestion = spans.map(|(lo, hi)| { let sm = cx.sess().source_map(); - let lo_replace = - if (keep_space.0 || is_kw) && - let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') { - " " - } else { - "" - }; + let lo_replace = if (keep_space.0 || is_kw) + && let Ok(snip) = sm.span_to_prev_source(lo) + && !snip.ends_with(' ') + { + " " + } else { + "" + }; - let hi_replace = - if keep_space.1 && - let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') { - " " - } else { - "" - }; + let hi_replace = if keep_space.1 + && let Ok(snip) = sm.span_to_next_source(hi) + && !snip.starts_with(' ') + { + " " + } else { + "" + }; UnusedDelimSuggestion { start_span: lo, start_replace: lo_replace, @@ -1056,10 +1058,10 @@ impl UnusedParens { impl EarlyLintPass for UnusedParens { #[inline] fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ExprKind::Binary(op, lhs, _rhs) = &e.kind && - (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) && - let ExprKind::Cast(_expr, ty) = &lhs.kind && - let ast::TyKind::Paren(_) = &ty.kind + if let ExprKind::Binary(op, lhs, _rhs) = &e.kind + && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) + && let ExprKind::Cast(_expr, ty) = &lhs.kind + && let ast::TyKind::Paren(_) = &ty.kind { self.parens_in_cast_in_lt.push(ty.id); } @@ -1111,13 +1113,19 @@ impl EarlyLintPass for UnusedParens { } fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ExprKind::Binary(op, lhs, _rhs) = &e.kind && - (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) && - let ExprKind::Cast(_expr, ty) = &lhs.kind && - let ast::TyKind::Paren(_) = &ty.kind + if let ExprKind::Binary(op, lhs, _rhs) = &e.kind + && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) + && let ExprKind::Cast(_expr, ty) = &lhs.kind + && let ast::TyKind::Paren(_) = &ty.kind { - let id = self.parens_in_cast_in_lt.pop().expect("check_expr and check_expr_post must balance"); - assert_eq!(id, ty.id, "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"); + let id = self + .parens_in_cast_in_lt + .pop() + .expect("check_expr and check_expr_post must balance"); + assert_eq!( + id, ty.id, + "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor" + ); } } @@ -1146,7 +1154,7 @@ impl EarlyLintPass for UnusedParens { fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { if let StmtKind::Local(ref local) = s.kind { - self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false)); + self.check_unused_parens_pat(cx, &local.pat, true, false, (true, false)); } <Self as UnusedDelimLint>::check_stmt(self, cx, s) @@ -1161,8 +1169,8 @@ impl EarlyLintPass for UnusedParens { } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { - if let ast::TyKind::Paren(_) = ty.kind && - Some(&ty.id) == self.parens_in_cast_in_lt.last() + if let ast::TyKind::Paren(_) = ty.kind + && Some(&ty.id) == self.parens_in_cast_in_lt.last() { return; } @@ -1206,13 +1214,14 @@ impl EarlyLintPass for UnusedParens { fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) { use rustc_ast::{WhereBoundPredicate, WherePredicate}; if let WherePredicate::BoundPredicate(WhereBoundPredicate { - bounded_ty, - bound_generic_params, - .. - }) = pred && - let ast::TyKind::Paren(_) = &bounded_ty.kind && - bound_generic_params.is_empty() { - self.with_self_ty_parens = true; + bounded_ty, + bound_generic_params, + .. + }) = pred + && let ast::TyKind::Paren(_) = &bounded_ty.kind + && bound_generic_params.is_empty() + { + self.with_self_ty_parens = true; } } @@ -1516,9 +1525,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { match e.kind { hir::ExprKind::Call(path_expr, [_]) if let hir::ExprKind::Path(qpath) = &path_expr.kind - && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() - && cx.tcx.is_diagnostic_item(sym::box_new, did) - => {} + && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::box_new, did) => {} _ => return, } |