diff --git a/.cargo/config.toml b/.cargo/config.toml index f3dd9275a42..4d80d3ce63d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -11,3 +11,6 @@ target-dir = "target" [unstable] binary-dep-depinfo = true + +[profile.dev] +split-debuginfo = "unpacked" diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 24e677ce8e1..93198aabdb5 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -180,6 +180,8 @@ jobs: # Run - name: Build Integration Test + env: + CARGO_PROFILE_DEV_SPLIT_DEBUGINFO: off run: cargo test --test integration --features integration --no-run # Upload diff --git a/CHANGELOG.md b/CHANGELOG.md index 81d0ff80968..8fde8c6d902 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4988,6 +4988,7 @@ Released 2018-09-13 [`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc [`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by +[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps diff --git a/COPYRIGHT b/COPYRIGHT index a6be75b5e31..82703b18fd7 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,3 +1,5 @@ +// REUSE-IgnoreStart + Copyright 2014-2022 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license , at your option. All files in the project carrying such notice may not be copied, modified, or distributed except according to those terms. + +// REUSE-IgnoreEnd diff --git a/README.md b/README.md index 3e7379ace7e..b69ed8900a4 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,8 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT ## License + + Copyright 2014-2022 The Rust Project Developers Licensed under the Apache License, Version 2.0 , at your option. Files in the project may not be copied, modified, or distributed except according to those terms. + + diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index f57dc627dce..0f5ee7103de 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -18,6 +18,7 @@ because that's clearly a non-descriptive name. - [Cargo lints](#cargo-lints) - [Rustfix tests](#rustfix-tests) - [Testing manually](#testing-manually) + - [Running directly](#running-directly) - [Lint declaration](#lint-declaration) - [Lint registration](#lint-registration) - [Lint passes](#lint-passes) @@ -186,6 +187,15 @@ cargo dev lint input.rs from the working copy root. With tests in place, let's have a look at implementing our lint now. +## Running directly + +While it's easier to just use `cargo dev lint`, it might be desirable to get +`target/release/cargo-clippy` and `target/release/clippy-driver` to work as well in some cases. +By default, they don't work because clippy dynamically links rustc. To help them find rustc, +add the path printed by`rustc --print target-libdir` (ran inside this workspace so that the rustc version matches) +to your library search path. +On linux, this can be done by setting the `LD_LIBRARY_PATH` environment variable to that path. + ## Lint declaration Let's start by opening the new file created in the `clippy_lints` crate at diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index e8106beec37..29fde9336c0 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -495,18 +495,19 @@ struct NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind { - if let Some(suggestion) = simplify_not(self.cx, inner) { - span_lint_and_sugg( - self.cx, - NONMINIMAL_BOOL, - expr.span, - "this boolean expression can be simplified", - "try", - suggestion, - Applicability::MachineApplicable, - ); - } + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && + !inner.span.from_expansion() && + let Some(suggestion) = simplify_not(self.cx, inner) + { + span_lint_and_sugg( + self.cx, + NONMINIMAL_BOOL, + expr.span, + "this boolean expression can be simplified", + "try", + suggestion, + Applicability::MachineApplicable, + ); } walk_expr(self, expr); diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 823970e35ab..95c2ecbf791 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -2,8 +2,9 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::expr_or_init; use clippy_utils::source::snippet; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::{Applicability, Diagnostic, SuggestionStyle}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -163,19 +164,34 @@ pub(super) fn check( _ => return, }; - let name_of_cast_from = snippet(cx, cast_expr.span, ".."); - let cast_to_snip = snippet(cx, cast_to_span, ".."); - let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})"); - span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| { diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ..."); - diag.span_suggestion_with_style( - expr.span, - "... or use `try_from` and handle the error accordingly", - suggestion, - Applicability::Unspecified, - // always show the suggestion in a separate line - SuggestionStyle::ShowAlways, - ); + if !cast_from.is_floating_point() { + offer_suggestion(cx, expr, cast_expr, cast_to_span, diag); + } }); } + +fn offer_suggestion( + cx: &LateContext<'_>, + expr: &Expr<'_>, + cast_expr: &Expr<'_>, + cast_to_span: Span, + diag: &mut Diagnostic, +) { + let cast_to_snip = snippet(cx, cast_to_span, ".."); + let suggestion = if cast_to_snip == "_" { + format!("{}.try_into()", Sugg::hir(cx, cast_expr, "..").maybe_par()) + } else { + format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, "..")) + }; + + diag.span_suggestion_with_style( + expr.span, + "... or use `try_from` and handle the error accordingly", + suggestion, + Applicability::Unspecified, + // always show the suggestion in a separate line + SuggestionStyle::ShowAlways, + ); +} diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index e8531157e0f..a8926b29ac8 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { span: Span, def_id: LocalDefId, ) { - if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) { + if !cx.tcx.has_attr(def_id, sym::test) { let expr = if is_async_fn(kind) { match get_async_fn_body(cx.tcx, body) { Some(b) => b, diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f7b108c923a..15b557bded2 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -619,6 +619,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, + crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO, crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO, crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO, crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO, diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 8a5a28c6b3d..8f68f90a2a1 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { self_ty, .. }) = item.kind; - if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); if !item.span.from_expansion(); if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::Default, def_id); diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 1a9dad47839..f425dd5fb70 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { }) = item.kind { let ty = cx.tcx.type_of(item.owner_id).subst_identity(); - let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 084190f0013..c9fad98e437 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -32,7 +32,7 @@ declare_clippy_lint! { /// ### Example /// ```rust /// // Assuming that `clippy.toml` contains the following line: - /// // allowed-locales = ["Latin", "Cyrillic"] + /// // allowed-scripts = ["Latin", "Cyrillic"] /// let counter = 10; // OK, latin is allowed. /// let счётчик = 10; // OK, cyrillic is allowed. /// let zähler = 10; // OK, it's still latin. diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 29bdc46b647..1e9e826631c 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -22,13 +22,13 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { + } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, sig.decl, @@ -47,13 +47,10 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public - && !is_proc_macro(cx.sess(), attrs) - && trait_ref_of_method(cx, item.owner_id.def_id).is_none() - { + } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( cx, sig.decl, @@ -73,12 +70,12 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let attrs = cx.tcx.hir().attrs(item.hir_id()); - let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use); + let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); - if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) { + if attr.is_none() && is_public && !is_proc_macro(attrs) { check_must_use_candidate( cx, sig.decl, diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 9fb73a371b8..ed0bd58c770 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::traits::{self, FulfillmentError}; +use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { /// ### What it does @@ -79,8 +79,10 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); - let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait); + ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); + let send_errors = ocx.select_all_or_error(); if !send_errors.is_empty() { span_lint_and_then( cx, diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index d1d2db27c6f..fe28c526be3 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -167,7 +167,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { Finite }, ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), - ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), + ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), ExprKind::Call(path, _) => { if let ExprKind::Path(ref qpath) = path.kind { cx.qpath_res(qpath, path.hir_id) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 100cba45679..c9210bf73f8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -302,6 +302,7 @@ mod unit_types; mod unnamed_address; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; +mod unnecessary_struct_initialization; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; @@ -938,6 +939,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); + store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index b1bc10802e1..f0a1b1dfe56 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -124,8 +124,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t #[allow(clippy::too_many_lines)] fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: HirId) -> NeverLoopResult { match expr.kind { - ExprKind::Box(e) - | ExprKind::Unary(_, e) + ExprKind::Unary(_, e) | ExprKind::Cast(e, _) | ExprKind::Type(e, _) | ExprKind::Field(e, _) diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index c7254b32d0b..577bc1d661d 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::match_function_call_with_def_id; use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -184,16 +183,10 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> { if_chain! { if let Some(block_expr) = block.expr; - if let Some(args) = cx - .tcx - .lang_items() - .identity_future_fn() - .and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id)); - if args.len() == 1; if let Expr { kind: ExprKind::Closure(&Closure { body, .. }), .. - } = args[0]; + } = block_expr; let closure_body = cx.tcx.hir().body(body); if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); then { diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index b33a2478172..04225beeb70 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -321,7 +321,6 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { self.has_significant_drop = true; } } - ExprKind::Box(..) | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Unary(..) | diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 5201da52bbf..67618f7038a 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -33,10 +33,6 @@ struct SortByKeyDetection { /// contains a and the other replaces it with b) fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { match (&a_expr.kind, &b_expr.kind) { - // Two boxes with mirrored contents - (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { - mirrored_exprs(left_expr, a_ident, right_expr, b_ident) - }, // Two arrays with mirrored contents (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index df26b36b7b3..4c4c003ca46 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -369,10 +369,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) - && Inherited::build(cx.tcx, item.owner_id.def_id).enter(|inherited| { - let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.owner_id.def_id); - fn_ctxt.can_coerce(ty, output_ty) - }) { + && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) + && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) + && fn_ctxt.can_coerce(ty, output_ty) + { if has_lifetime(output_ty) && has_lifetime(ty) { return false; } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 79c1ae4861e..e3712190e67 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -127,8 +127,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ExprKind::Type(inner, _) | ExprKind::Unary(_, inner) | ExprKind::Field(inner, _) - | ExprKind::AddrOf(_, _, inner) - | ExprKind::Box(inner) => has_no_effect(cx, inner), + | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner), ExprKind::Struct(_, fields, ref base) => { !has_drop(cx, cx.typeck_results().expr_ty(expr)) && fields.iter().all(|field| has_no_effect(cx, field.expr)) @@ -234,8 +233,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option reduce_expression(cx, inner).or_else(|| Some(vec![inner])), + | ExprKind::AddrOf(_, _, inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), ExprKind::Struct(_, fields, ref base) => { if has_drop(cx, cx.typeck_results().expr_ty(expr)) { None diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 5aa3c6f2f93..a8c4823fe53 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if_chain! { if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; - if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived); + if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived); if let Some(eq_trait) = cx.tcx.lang_items().eq_trait(); if trait_ref.path.res.def_id() == eq_trait; then { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 87f966ced0d..ae7d19624ba 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -213,8 +213,7 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_ } loop { expr = match expr.kind { - ExprKind::Box(e) - | ExprKind::AddrOf(_, _, e) + ExprKind::AddrOf(_, _, e) | ExprKind::Block( &Block { stmts: [], diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index e2d90edec5a..869358fb1ba 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,9 +1,9 @@ -use crate::FxHashSet; use clippy_utils::{ diagnostics::span_lint_and_then, get_attr, source::{indent_of, snippet}, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{ self as hir, @@ -58,6 +58,7 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); pub struct SignificantDropTightening<'tcx> { /// Auxiliary structure used to avoid having to verify the same type multiple times. seen_types: FxHashSet>, + type_cache: FxHashMap, bool>, } impl<'tcx> SignificantDropTightening<'tcx> { @@ -118,7 +119,7 @@ impl<'tcx> SignificantDropTightening<'tcx> { stmt: &hir::Stmt<'_>, cb: impl Fn(&mut SigDropAuxParams), ) { - let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types); + let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache); sig_drop_finder.visit_expr(expr); if sig_drop_finder.has_sig_drop { cb(sdap); @@ -296,15 +297,24 @@ impl Default for SigDropAuxParams { struct SigDropChecker<'cx, 'sdt, 'tcx> { cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, } impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { - pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + pub(crate) fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, + ) -> Self { seen_types.clear(); - Self { cx, seen_types } + Self { + cx, + seen_types, + type_cache, + } } - pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { let mut iter = get_attr( self.cx.sess(), @@ -340,6 +350,16 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { } } + pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + // The borrow checker prevents us from using something fancier like or_insert_with. + if let Some(ty) = self.type_cache.get(&ty) { + return *ty; + } + let value = self.has_sig_drop_attr_uncached(ty); + self.type_cache.insert(ty, value); + value + } + fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { !self.seen_types.insert(ty) } @@ -353,11 +373,15 @@ struct SigDropFinder<'cx, 'sdt, 'tcx> { } impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { - fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { + fn new( + cx: &'cx LateContext<'tcx>, + seen_types: &'sdt mut FxHashSet>, + type_cache: &'sdt mut FxHashMap, bool>, + ) -> Self { Self { cx, has_sig_drop: false, - sig_drop_checker: SigDropChecker::new(cx, seen_types), + sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache), } } } @@ -380,7 +404,6 @@ impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { | hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Binary(..) - | hir::ExprKind::Box(..) | hir::ExprKind::Call(..) | hir::ExprKind::Field(..) | hir::ExprKind::If(..) diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index e111c7d2291..8aa47b62ebf 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -596,8 +596,7 @@ fn ident_difference_expr_with_base_location( | (MethodCall(_), MethodCall(_)) | (Call(_, _), Call(_, _)) | (ConstBlock(_), ConstBlock(_)) - | (Array(_), Array(_)) - | (Box(_), Box(_)) => { + | (Array(_), Array(_)) => { // keep going }, _ => { diff --git a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 8530b43243f..85cd74f23ef 100644 --- a/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -2,8 +2,9 @@ use super::utils::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; +use rustc_ast::ExprPrecedence; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, Node}; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; @@ -19,7 +20,7 @@ pub(super) fn check<'tcx>( ) -> bool { use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; let mut app = Applicability::MachineApplicable; - let sugg = match check_cast(cx, e, from_ty, to_ty) { + let mut sugg = match check_cast(cx, e, from_ty, to_ty) { Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) .as_ty(to_ty.to_string()) @@ -39,6 +40,12 @@ pub(super) fn check<'tcx>( _ => return false, }; + if let Node::Expr(parent) = cx.tcx.hir().get_parent(e.hir_id) + && parent.precedence().order() > ExprPrecedence::Cast.order() + { + sugg = format!("({sugg})"); + } + span_lint_and_sugg( cx, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, diff --git a/clippy_lints/src/transmute/utils.rs b/clippy_lints/src/transmute/utils.rs index cddaf9450ea..62efd13b8d9 100644 --- a/clippy_lints/src/transmute/utils.rs +++ b/clippy_lints/src/transmute/utils.rs @@ -33,38 +33,37 @@ pub(super) fn check_cast<'tcx>( let hir_id = e.hir_id; let local_def_id = hir_id.owner.def_id; - Inherited::build(cx.tcx, local_def_id).enter(|inherited| { - let fn_ctxt = FnCtxt::new(inherited, cx.param_env, local_def_id); + let inherited = Inherited::new(cx.tcx, local_def_id); + let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id); - // If we already have errors, we can't be sure we can pointer cast. + // If we already have errors, we can't be sure we can pointer cast. + assert!( + !fn_ctxt.errors_reported_since_creation(), + "Newly created FnCtxt contained errors" + ); + + if let Ok(check) = cast::CastCheck::new( + &fn_ctxt, + e, + from_ty, + to_ty, + // We won't show any error to the user, so we don't care what the span is here. + DUMMY_SP, + DUMMY_SP, + hir::Constness::NotConst, + ) { + let res = check.do_check(&fn_ctxt); + + // do_check's documentation says that it might return Ok and create + // errors in the fcx instead of returning Err in some cases. Those cases + // should be filtered out before getting here. assert!( !fn_ctxt.errors_reported_since_creation(), - "Newly created FnCtxt contained errors" + "`fn_ctxt` contained errors after cast check!" ); - if let Ok(check) = cast::CastCheck::new( - &fn_ctxt, - e, - from_ty, - to_ty, - // We won't show any error to the user, so we don't care what the span is here. - DUMMY_SP, - DUMMY_SP, - hir::Constness::NotConst, - ) { - let res = check.do_check(&fn_ctxt); - - // do_check's documentation says that it might return Ok and create - // errors in the fcx instead of returning Err in some cases. Those cases - // should be filtered out before getting here. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "`fn_ctxt` contained errors after cast check!" - ); - - res.ok() - } else { - None - } - }) + res.ok() + } else { + None + } } diff --git a/clippy_lints/src/unnecessary_struct_initialization.rs b/clippy_lints/src/unnecessary_struct_initialization.rs new file mode 100644 index 00000000000..af0b4b1592f --- /dev/null +++ b/clippy_lints/src/unnecessary_struct_initialization.rs @@ -0,0 +1,84 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_expr, path_to_local, source::snippet, ty::is_copy}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for initialization of a `struct` by copying a base without setting + /// any field. + /// + /// ### Why is this bad? + /// Readibility suffers from unnecessary struct building. + /// + /// ### Example + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = S { ..a }; + /// ``` + /// Use instead: + /// ```rust + /// struct S { s: String } + /// + /// let a = S { s: String::from("Hello, world!") }; + /// let b = a; + /// ``` + #[clippy::version = "1.70.0"] + pub UNNECESSARY_STRUCT_INITIALIZATION, + complexity, + "struct built from a base that can be written mode concisely" +} +declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]); + +impl LateLintPass<'_> for UnnecessaryStruct { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Struct(_, &[], Some(base)) = expr.kind { + if let Some(parent) = get_parent_expr(cx, expr) && + let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) && + parent_ty.is_any_ptr() + { + if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() { + // When the type implements `Copy`, a reference to the new struct works on the + // copy. Using the original would borrow it. + return; + } + + if parent_ty.is_mutable_ptr() && !is_mutable(cx, base) { + // The original can be used in a mutable reference context only if it is mutable. + return; + } + } + + // TODO: do not propose to replace *XX if XX is not Copy + if let ExprKind::Unary(UnOp::Deref, target) = base.kind && + matches!(target.kind, ExprKind::Path(..)) && + !is_copy(cx, cx.typeck_results().expr_ty(expr)) + { + // `*base` cannot be used instead of the struct in the general case if it is not Copy. + return; + } + + span_lint_and_sugg( + cx, + UNNECESSARY_STRUCT_INITIALIZATION, + expr.span, + "unnecessary struct building", + "replace with", + snippet(cx, base.span, "..").into_owned(), + rustc_errors::Applicability::MachineApplicable, + ); + } + } +} + +fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(hir_id) = path_to_local(expr) && + let Node::Pat(pat) = cx.tcx.hir().get(hir_id) + { + matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..)) + } else { + true + } +} diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index f31c3fdb095..bc4adf1596d 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -395,11 +395,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } self.expr(field!(let_expr.init)); }, - ExprKind::Box(inner) => { - bind!(self, inner); - kind!("Box({inner})"); - self.expr(inner); - }, ExprKind::Array(elements) => { bind!(self, elements); kind!("Array({elements})"); diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index d82098523e3..809d654603a 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), (Err, Err) => true, - (Box(l), Box(r)) | (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r), + (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value), diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 7987a233bdc..b4ad42a5027 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -145,8 +145,8 @@ pub fn get_unique_attr<'a>( /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise -pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| sess.is_proc_macro_attr(attr)) +pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { + attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr) } /// Return true if the attributes contain `#[doc(hidden)]` diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 43f0df145f0..d3a6929f67e 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -112,7 +112,6 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { /// Get the search patterns to use for the given expression fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { match e.kind { - ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1), ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index ee2f816f181..28c85717061 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -199,11 +199,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, // Memory allocation, custom operator, loop, or call to an unknown function - ExprKind::Box(_) - | ExprKind::Unary(..) - | ExprKind::Binary(..) - | ExprKind::Loop(..) - | ExprKind::Call(..) => self.eagerness = Lazy, + ExprKind::Unary(..) | ExprKind::Binary(..) | ExprKind::Loop(..) | ExprKind::Call(..) => { + self.eagerness = Lazy; + }, ExprKind::ConstBlock(_) | ExprKind::Array(_) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 0603755f8a9..3a6d23ca5c1 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -249,7 +249,6 @@ impl HirEqInterExpr<'_, '_, '_> { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) && both(le, re, |l, r| self.eq_expr(l, r)) }, - (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r), (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => { self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) }, @@ -628,7 +627,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(j); } }, - ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { + ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); }, ExprKind::Call(fun, args) => { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 0fdbd7a6341..e8225feb33d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1923,16 +1923,7 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool { /// Peels away all the compiler generated code surrounding the body of an async function, pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Call( - _, - &[ - Expr { - kind: ExprKind::Closure(&Closure { body, .. }), - .. - }, - ], - ) = body.value.kind - { + if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind { if let ExprKind::Block( Block { stmts: [], diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index e135bd9feee..c0e32068eca 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -533,6 +533,14 @@ struct FormatArgsValues<'tcx> { } impl<'tcx> FormatArgsValues<'tcx> { + fn new_empty(format_string_span: SpanData) -> Self { + Self { + value_args: Vec::new(), + pos_to_value_index: Vec::new(), + format_string_span, + } + } + fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { let mut pos_to_value_index = Vec::new(); let mut value_args = Vec::new(); @@ -997,12 +1005,13 @@ impl<'tcx> FormatArgsExpn<'tcx> { .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?; let newline = macro_name == sym::format_args_nl; + // ::core::fmt::Arguments::new_const(pieces) // ::core::fmt::Arguments::new_v1(pieces, args) // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) - if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind + if let ExprKind::Call(callee, [pieces, rest @ ..]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind - && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted") + && matches!(seg.ident.as_str(), "new_const" | "new_v1" | "new_v1_formatted") { let format_string = FormatString::new(cx, pieces)?; @@ -1026,7 +1035,7 @@ impl<'tcx> FormatArgsExpn<'tcx> { return None; } - let positions = if let Some(fmt_arg) = rest.first() { + let positions = if let Some(fmt_arg) = rest.get(1) { // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse // them. @@ -1042,7 +1051,11 @@ impl<'tcx> FormatArgsExpn<'tcx> { })) }; - let values = FormatArgsValues::new(args, format_string.span.data()); + let values = if let Some(args) = rest.first() { + FormatArgsValues::new(args, format_string.span.data()) + } else { + FormatArgsValues::new_empty(format_string.span.data()) + }; let args = izip!(positions, parsed_args, parser.arg_places) .map(|(position, parsed_arg, arg_span)| { diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index c00800291db..d66640ba0b7 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -37,7 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"), + ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"), ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"), ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"), ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"), @@ -176,6 +176,10 @@ fn check_rvalue<'tcx>( // FIXME(dyn-star) unimplemented!() }, + Rvalue::Cast(CastKind::Transmute, _, _) => Err(( + span, + "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(), + )), // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; @@ -241,6 +245,7 @@ fn check_statement<'tcx>( | StatementKind::StorageDead(_) | StatementKind::Retag { .. } | StatementKind::AscribeUserType(..) + | StatementKind::PlaceMention(..) | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter | StatementKind::Nop => Ok(()), diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 65f39daf89f..a5a4a921d94 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -125,7 +125,6 @@ impl<'a> Sugg<'a> { match expr.kind { hir::ExprKind::AddrOf(..) - | hir::ExprKind::Box(..) | hir::ExprKind::If(..) | hir::ExprKind::Let(..) | hir::ExprKind::Closure { .. } @@ -180,7 +179,6 @@ impl<'a> Sugg<'a> { match expr.kind { _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::AddrOf(..) - | ast::ExprKind::Box(..) | ast::ExprKind::Closure { .. } | ast::ExprKind::If(..) | ast::ExprKind::Let(..) diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index d27a20bd4df..1dc19bac984 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -599,10 +599,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Let(&Let { init: e, .. }) => { helper(typeck, false, e, f)?; }, - ExprKind::Block(&Block { expr: Some(e), .. }, _) - | ExprKind::Box(e) - | ExprKind::Cast(e, _) - | ExprKind::Unary(_, e) => { + ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => { helper(typeck, true, e, f)?; }, ExprKind::Call(callee, args) => { diff --git a/rust-toolchain b/rust-toolchain index d788c6359d7..0b2458ea007 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-03-10" +channel = "nightly-2023-03-24" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index eefc661f963..e197ea048a0 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -49,6 +49,8 @@ The changelog for `rustc_tools_util` is available under: ## License + + Copyright 2014-2022 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license , at your option. All files in the project carrying such notice may not be copied, modified, or distributed except according to those terms. + + diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index 7ed0ef0274f..b4619e980f3 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -9,3 +9,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +thread panicked while panicking. aborting. diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout index c6acf24c21e..eb3e5189c82 100644 --- a/tests/ui/author/blocks.stdout +++ b/tests/ui/author/blocks.stdout @@ -43,11 +43,7 @@ if let ExprKind::Block(block, None) = expr.kind if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output && expr1 = &cx.tcx.hir().body(body_id).value - && let ExprKind::Call(func, args) = expr1.kind - && let ExprKind::Path(ref qpath) = func.kind - && matches!(qpath, QPath::LangItem(LangItem::IdentityFuture, _)) - && args.len() == 1 - && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind + && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind && let FnRetTy::DefaultReturn(_) = fn_decl1.output && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind diff --git a/tests/ui/boxed_local.rs b/tests/ui/boxed_local.rs index 4639f00a8d8..79b6d33fc77 100644 --- a/tests/ui/boxed_local.rs +++ b/tests/ui/boxed_local.rs @@ -1,4 +1,3 @@ -#![feature(box_syntax)] #![feature(lint_reasons)] #![allow( clippy::borrowed_box, @@ -34,7 +33,7 @@ fn ok_box_trait(boxed_trait: &Box) { } fn warn_call() { - let x = box A; + let x = Box::new(A); x.foo(); } @@ -43,41 +42,41 @@ fn warn_arg(x: Box) { } fn nowarn_closure_arg() { - let x = Some(box A); + let x = Some(Box::new(A)); x.map_or((), |x| take_ref(&x)); } fn warn_rename_call() { - let x = box A; + let x = Box::new(A); let y = x; y.foo(); // via autoderef } fn warn_notuse() { - let bz = box A; + let bz = Box::new(A); } fn warn_pass() { - let bz = box A; + let bz = Box::new(A); take_ref(&bz); // via deref coercion } fn nowarn_return() -> Box { - box A // moved out, "escapes" + Box::new(A) // moved out, "escapes" } fn nowarn_move() { - let bx = box A; + let bx = Box::new(A); drop(bx) // moved in, "escapes" } fn nowarn_call() { - let bx = box A; + let bx = Box::new(A); bx.clone(); // method only available to Box, not via autoderef } fn nowarn_pass() { - let bx = box A; + let bx = Box::new(A); take_box(&bx); // fn needs &Box } @@ -86,30 +85,20 @@ fn take_ref(x: &A) {} fn nowarn_ref_take() { // false positive, should actually warn - let x = box A; + let x = Box::new(A); let y = &x; take_box(y); } fn nowarn_match() { - let x = box A; // moved into a match + let x = Box::new(A); // moved into a match match x { y => drop(y), } } fn warn_match() { - let x = box A; - match &x { - // not moved - y => (), - } -} - -fn nowarn_large_array() { - // should not warn, is large array - // and should not be on stack - let x = box [1; 10000]; + let x = Box::new(A); match &x { // not moved y => (), diff --git a/tests/ui/boxed_local.stderr b/tests/ui/boxed_local.stderr index 9036529f39c..10d78fbc0ab 100644 --- a/tests/ui/boxed_local.stderr +++ b/tests/ui/boxed_local.stderr @@ -1,5 +1,5 @@ error: local variable doesn't need to be boxed here - --> $DIR/boxed_local.rs:41:13 + --> $DIR/boxed_local.rs:40:13 | LL | fn warn_arg(x: Box) { | ^ @@ -7,19 +7,19 @@ LL | fn warn_arg(x: Box) { = note: `-D clippy::boxed-local` implied by `-D warnings` error: local variable doesn't need to be boxed here - --> $DIR/boxed_local.rs:132:12 + --> $DIR/boxed_local.rs:121:12 | LL | pub fn new(_needs_name: Box>) -> () {} | ^^^^^^^^^^^ error: local variable doesn't need to be boxed here - --> $DIR/boxed_local.rs:196:44 + --> $DIR/boxed_local.rs:185:44 | LL | fn default_impl_x(self: Box, x: Box) -> u32 { | ^ error: local variable doesn't need to be boxed here - --> $DIR/boxed_local.rs:203:16 + --> $DIR/boxed_local.rs:192:16 | LL | fn foo(x: Box) {} | ^ diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 8b2673c2a7f..a86b85706a3 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -29,6 +29,12 @@ fn main() { 1f64 as isize; 1f64 as usize; 1f32 as u32 as u16; + { + let _x: i8 = 1i32 as _; + 1f32 as i32; + 1f64 as i32; + 1f32 as u8; + } // Test clippy::cast_possible_wrap 1u8 as i8; 1u16 as i16; diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 451078de23b..65ecf1aa37a 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -44,10 +44,6 @@ LL | 1f32 as i32; | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` -help: ... or use `try_from` and handle the error accordingly - | -LL | i32::try_from(1f32); - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value --> $DIR/cast.rs:25:5 @@ -56,10 +52,6 @@ LL | 1f32 as u32; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | u32::try_from(1f32); - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may lose the sign of the value --> $DIR/cast.rs:25:5 @@ -76,10 +68,6 @@ LL | 1f64 as f32; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | f32::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~ error: casting `i32` to `i8` may truncate the value --> $DIR/cast.rs:27:5 @@ -112,10 +100,6 @@ LL | 1f64 as isize; | ^^^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | isize::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may truncate the value --> $DIR/cast.rs:30:5 @@ -124,10 +108,6 @@ LL | 1f64 as usize; | ^^^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | usize::try_from(1f64); - | ~~~~~~~~~~~~~~~~~~~~~ error: casting `f64` to `usize` may lose the sign of the value --> $DIR/cast.rs:30:5 @@ -154,10 +134,6 @@ LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ | = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... -help: ... or use `try_from` and handle the error accordingly - | -LL | u32::try_from(1f32) as u16; - | ~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may lose the sign of the value --> $DIR/cast.rs:31:5 @@ -165,8 +141,50 @@ error: casting `f32` to `u32` may lose the sign of the value LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ +error: casting `i32` to `i8` may truncate the value + --> $DIR/cast.rs:33:22 + | +LL | let _x: i8 = 1i32 as _; + | ^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | let _x: i8 = 1i32.try_into(); + | ~~~~~~~~~~~~~~~ + +error: casting `f32` to `i32` may truncate the value + --> $DIR/cast.rs:34:9 + | +LL | 1f32 as i32; + | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f64` to `i32` may truncate the value + --> $DIR/cast.rs:35:9 + | +LL | 1f64 as i32; + | ^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f32` to `u8` may truncate the value + --> $DIR/cast.rs:36:9 + | +LL | 1f32 as u8; + | ^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: casting `f32` to `u8` may lose the sign of the value + --> $DIR/cast.rs:36:9 + | +LL | 1f32 as u8; + | ^^^^^^^^^^ + error: casting `u8` to `i8` may wrap around the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:39:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -174,43 +192,43 @@ LL | 1u8 as i8; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting `u16` to `i16` may wrap around the value - --> $DIR/cast.rs:34:5 + --> $DIR/cast.rs:40:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> $DIR/cast.rs:35:5 + --> $DIR/cast.rs:41:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> $DIR/cast.rs:36:5 + --> $DIR/cast.rs:42:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> $DIR/cast.rs:37:5 + --> $DIR/cast.rs:43:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:40:5 + --> $DIR/cast.rs:46:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:42:5 + --> $DIR/cast.rs:48:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:109:5 + --> $DIR/cast.rs:115:5 | LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +240,7 @@ LL | i8::try_from((-99999999999i64).min(1)); // should be linted because sig | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:121:5 + --> $DIR/cast.rs:127:5 | LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -234,7 +252,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> $DIR/cast.rs:142:21 + --> $DIR/cast.rs:148:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -246,7 +264,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> $DIR/cast.rs:143:21 + --> $DIR/cast.rs:149:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -254,7 +272,7 @@ LL | let _ = Self::B as u8; = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` error: casting `main::E5` to `i8` may truncate the value - --> $DIR/cast.rs:179:21 + --> $DIR/cast.rs:185:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -266,13 +284,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> $DIR/cast.rs:180:21 + --> $DIR/cast.rs:186:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> $DIR/cast.rs:194:21 + --> $DIR/cast.rs:200:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -284,7 +302,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:209:21 + --> $DIR/cast.rs:215:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -296,7 +314,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> $DIR/cast.rs:250:21 + --> $DIR/cast.rs:256:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -308,7 +326,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:258:13 + --> $DIR/cast.rs:264:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -316,11 +334,11 @@ LL | let c = (q >> 16) as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | -LL | let c = u8::try_from((q >> 16)); - | ~~~~~~~~~~~~~~~~~~~~~~~ +LL | let c = u8::try_from(q >> 16); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:261:13 + --> $DIR/cast.rs:267:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -328,8 +346,8 @@ LL | let c = (q / 1000) as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... help: ... or use `try_from` and handle the error accordingly | -LL | let c = u8::try_from((q / 1000)); - | ~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let c = u8::try_from(q / 1000); + | ~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 36 previous errors +error: aborting due to 41 previous errors diff --git a/tests/ui/erasing_op.rs b/tests/ui/erasing_op.rs index ae2fad0086d..74985029e00 100644 --- a/tests/ui/erasing_op.rs +++ b/tests/ui/erasing_op.rs @@ -31,9 +31,7 @@ impl core::ops::Mul for Vec1 { #[allow(clippy::no_effect)] #[warn(clippy::erasing_op)] -fn main() { - let x: u8 = 0; - +fn test(x: u8) { x * 0; 0 & x; 0 / x; @@ -41,3 +39,7 @@ fn main() { 0 * Vec1 { x: 5 }; Vec1 { x: 5 } * 0; } + +fn main() { + test(0) +} diff --git a/tests/ui/erasing_op.stderr b/tests/ui/erasing_op.stderr index 165ed9bfe58..97941252355 100644 --- a/tests/ui/erasing_op.stderr +++ b/tests/ui/erasing_op.stderr @@ -1,5 +1,5 @@ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:37:5 + --> $DIR/erasing_op.rs:35:5 | LL | x * 0; | ^^^^^ @@ -7,25 +7,25 @@ LL | x * 0; = note: `-D clippy::erasing-op` implied by `-D warnings` error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:38:5 + --> $DIR/erasing_op.rs:36:5 | LL | 0 & x; | ^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:39:5 + --> $DIR/erasing_op.rs:37:5 | LL | 0 / x; | ^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:41:5 + --> $DIR/erasing_op.rs:39:5 | LL | 0 * Vec1 { x: 5 }; | ^^^^^^^^^^^^^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> $DIR/erasing_op.rs:42:5 + --> $DIR/erasing_op.rs:40:5 | LL | Vec1 { x: 5 } * 0; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs index 67f24b4548a..8dfdee662b9 100644 --- a/tests/ui/integer_arithmetic.rs +++ b/tests/ui/integer_arithmetic.rs @@ -4,7 +4,7 @@ #[rustfmt::skip] fn main() { let mut i = 1i32; - let mut var1 = 0i32; + let mut var1 = 13i32; let mut var2 = -1i32; 1 + i; i * 2; diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index b93ff048a62..4e8517cad10 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_update)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::unnecessary_struct_initialization)] struct S { pub a: i32, diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index f08eb092e6b..1e42e1fbabf 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,7 +1,12 @@ -#![feature(box_syntax, fn_traits, unboxed_closures)] +#![feature(fn_traits, unboxed_closures)] #![warn(clippy::no_effect_underscore_binding)] #![allow(dead_code, path_statements)] -#![allow(clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args)] +#![allow( + clippy::deref_addrof, + clippy::redundant_field_names, + clippy::uninlined_format_args, + clippy::unnecessary_struct_initialization +)] struct Unit; struct Tuple(i32); @@ -102,7 +107,6 @@ fn main() { *&42; &6; (5, 6, 7); - box 42; ..; 5..; ..5; diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index 6a1e636f9a6..f10f2bcf2a8 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:92:5 + --> $DIR/no_effect.rs:97:5 | LL | 0; | ^^ @@ -7,157 +7,151 @@ LL | 0; = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:93:5 + --> $DIR/no_effect.rs:98:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:94:5 + --> $DIR/no_effect.rs:99:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:95:5 + --> $DIR/no_effect.rs:100:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:96:5 + --> $DIR/no_effect.rs:101:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:97:5 + --> $DIR/no_effect.rs:102:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:98:5 + --> $DIR/no_effect.rs:103:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:99:5 + --> $DIR/no_effect.rs:104:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:100:5 + --> $DIR/no_effect.rs:105:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:106:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:102:5 + --> $DIR/no_effect.rs:107:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:108:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:104:5 + --> $DIR/no_effect.rs:109:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:105:5 - | -LL | box 42; - | ^^^^^^^ - -error: statement with no effect - --> $DIR/no_effect.rs:106:5 + --> $DIR/no_effect.rs:110:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:111:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:108:5 + --> $DIR/no_effect.rs:112:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:113:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:110:5 + --> $DIR/no_effect.rs:114:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:115:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:112:5 + --> $DIR/no_effect.rs:116:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:117:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:114:5 + --> $DIR/no_effect.rs:118:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:115:5 + --> $DIR/no_effect.rs:119:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:117:5 + --> $DIR/no_effect.rs:121:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:119:5 + --> $DIR/no_effect.rs:123:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:120:5 + --> $DIR/no_effect.rs:124:5 | LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ @@ -165,22 +159,22 @@ LL | let _unused = 1; = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:121:5 + --> $DIR/no_effect.rs:125:5 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:122:5 + --> $DIR/no_effect.rs:126:5 | LL | let _duck = Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:123:5 + --> $DIR/no_effect.rs:127:5 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 30 previous errors +error: aborting due to 29 previous errors diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index e9b4367ca65..3b5a374b4a7 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -63,3 +63,32 @@ fn issue9428() { println!("foo"); } } + +fn issue_10523() { + macro_rules! a { + ($v:expr) => { + $v.is_some() + }; + } + let x: Option = None; + if !a!(x) {} +} + +fn issue_10523_1() { + macro_rules! a { + ($v:expr) => { + !$v.is_some() + }; + } + let x: Option = None; + if a!(x) {} +} + +fn issue_10523_2() { + macro_rules! a { + () => { + !None::.is_some() + }; + } + if a!() {} +} diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index 5db75f5291b..e1e30114081 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -1,9 +1,6 @@ #![warn(clippy::overflow_check_conditional)] -fn main() { - let a: u32 = 1; - let b: u32 = 2; - let c: u32 = 3; +fn test(a: u32, b: u32, c: u32) { if a + b < a {} if a > a + b {} if a + b < b {} @@ -23,3 +20,7 @@ fn main() { if i > i + j {} if i - j < i {} } + +fn main() { + test(1, 2, 3) +} diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr index 1b8b146b60a..92d1d8ef911 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/overflow_check_conditional.stderr @@ -1,5 +1,5 @@ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:7:8 + --> $DIR/overflow_check_conditional.rs:4:8 | LL | if a + b < a {} | ^^^^^^^^^ @@ -7,43 +7,43 @@ LL | if a + b < a {} = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:8:8 + --> $DIR/overflow_check_conditional.rs:5:8 | LL | if a > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:9:8 + --> $DIR/overflow_check_conditional.rs:6:8 | LL | if a + b < b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:10:8 + --> $DIR/overflow_check_conditional.rs:7:8 | LL | if b > a + b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:11:8 + --> $DIR/overflow_check_conditional.rs:8:8 | LL | if a - b > b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:12:8 + --> $DIR/overflow_check_conditional.rs:9:8 | LL | if b < a - b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:13:8 + --> $DIR/overflow_check_conditional.rs:10:8 | LL | if a - b > a {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:14:8 + --> $DIR/overflow_check_conditional.rs:11:8 | LL | if a < a - b {} | ^^^^^^^^^ diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/tests/ui/transmutes_expressible_as_ptr_casts.fixed index 55307506eb3..cc84ba25bd0 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -4,7 +4,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr)] use std::mem::{size_of, transmute}; @@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair { unsafe { transmute::(in_param) } } + +fn issue_10449() { + fn f() {} + + let _x: u8 = unsafe { *(f as *const u8) }; +} diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.rs b/tests/ui/transmutes_expressible_as_ptr_casts.rs index e7360f3f9dc..aa65ab4dd24 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -4,7 +4,7 @@ // would otherwise be responsible for #![warn(clippy::useless_transmute)] #![warn(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)] +#![allow(unused, clippy::borrow_as_ptr)] use std::mem::{size_of, transmute}; @@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair { unsafe { transmute::(in_param) } } + +fn issue_10449() { + fn f() {} + + let _x: u8 = unsafe { *std::mem::transmute::(f) }; +} diff --git a/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/tests/ui/transmutes_expressible_as_ptr_casts.stderr index e862fcb67a4..58f5162c78e 100644 --- a/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -58,5 +58,11 @@ error: transmute from a reference to a pointer LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` -error: aborting due to 9 previous errors +error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead + --> $DIR/transmutes_expressible_as_ptr_casts.rs:84:28 + | +LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` + +error: aborting due to 10 previous errors diff --git a/tests/ui/unnecessary_operation.fixed b/tests/ui/unnecessary_operation.fixed index d37163570ab..b046694f8c6 100644 --- a/tests/ui/unnecessary_operation.fixed +++ b/tests/ui/unnecessary_operation.fixed @@ -1,7 +1,12 @@ // run-rustfix -#![feature(box_syntax)] -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); @@ -59,7 +64,6 @@ fn main() { 5;6;get_number(); get_number(); get_number(); - get_number(); 5;get_number(); 42;get_number(); assert!([42, 55].len() > get_usize()); diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs index a14fd4bca0e..9ed9679e938 100644 --- a/tests/ui/unnecessary_operation.rs +++ b/tests/ui/unnecessary_operation.rs @@ -1,7 +1,12 @@ // run-rustfix -#![feature(box_syntax)] -#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] +#![allow( + clippy::deref_addrof, + dead_code, + unused, + clippy::no_effect, + clippy::unnecessary_struct_initialization +)] #![warn(clippy::unnecessary_operation)] struct Tuple(i32); @@ -57,7 +62,6 @@ fn main() { *&get_number(); &get_number(); (5, 6, get_number()); - box get_number(); get_number()..; ..get_number(); 5..get_number(); diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr index f66d08ecb82..a1d0d93998a 100644 --- a/tests/ui/unnecessary_operation.stderr +++ b/tests/ui/unnecessary_operation.stderr @@ -1,5 +1,5 @@ error: unnecessary operation - --> $DIR/unnecessary_operation.rs:51:5 + --> $DIR/unnecessary_operation.rs:56:5 | LL | Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` @@ -7,109 +7,103 @@ LL | Tuple(get_number()); = note: `-D clippy::unnecessary-operation` implied by `-D warnings` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:52:5 + --> $DIR/unnecessary_operation.rs:57:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:53:5 + --> $DIR/unnecessary_operation.rs:58:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:54:5 + --> $DIR/unnecessary_operation.rs:59:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:55:5 + --> $DIR/unnecessary_operation.rs:60:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:56:5 + --> $DIR/unnecessary_operation.rs:61:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:57:5 + --> $DIR/unnecessary_operation.rs:62:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:58:5 + --> $DIR/unnecessary_operation.rs:63:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:59:5 + --> $DIR/unnecessary_operation.rs:64:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:60:5 - | -LL | box get_number(); - | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` - -error: unnecessary operation - --> $DIR/unnecessary_operation.rs:61:5 + --> $DIR/unnecessary_operation.rs:65:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:62:5 + --> $DIR/unnecessary_operation.rs:66:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:63:5 + --> $DIR/unnecessary_operation.rs:67:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:64:5 + --> $DIR/unnecessary_operation.rs:68:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:65:5 + --> $DIR/unnecessary_operation.rs:69:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:66:5 + --> $DIR/unnecessary_operation.rs:70:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:67:5 + --> $DIR/unnecessary_operation.rs:71:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:68:5 + --> $DIR/unnecessary_operation.rs:72:5 | LL | [42; 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:69:5 + --> $DIR/unnecessary_operation.rs:73:5 | LL | / { LL | | get_number() @@ -117,12 +111,12 @@ LL | | }; | |______^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> $DIR/unnecessary_operation.rs:72:5 + --> $DIR/unnecessary_operation.rs:76:5 | LL | / FooString { LL | | s: String::from("blah"), LL | | }; | |______^ help: statement can be reduced to: `String::from("blah");` -error: aborting due to 20 previous errors +error: aborting due to 19 previous errors diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed new file mode 100644 index 00000000000..b47129e4a36 --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.fixed @@ -0,0 +1,73 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + *self + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = a; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut b; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &f; + + // Should lint: the result of an expression is mutable + let h = &mut *Box::new(S { f: String::from("foo") }); + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut *Box::new(T { f: 5 }); +} diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs new file mode 100644 index 00000000000..63b11c626e5 --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.rs @@ -0,0 +1,77 @@ +// run-rustfix + +#![allow(unused)] +#![warn(clippy::unnecessary_struct_initialization)] + +struct S { + f: String, +} + +#[derive(Clone, Copy)] +struct T { + f: u32, +} + +struct U { + f: u32, +} + +impl Clone for U { + fn clone(&self) -> Self { + // Do not lint: `Self` does not implement `Copy` + Self { ..*self } + } +} + +#[derive(Copy)] +struct V { + f: u32, +} + +impl Clone for V { + fn clone(&self) -> Self { + // Lint: `Self` implements `Copy` + Self { ..*self } + } +} + +fn main() { + // Should lint: `a` would be consumed anyway + let a = S { f: String::from("foo") }; + let mut b = S { ..a }; + + // Should lint: `b` would be consumed, and is mutable + let c = &mut S { ..b }; + + // Should not lint as `d` is not mutable + let d = S { f: String::from("foo") }; + let e = &mut S { ..d }; + + // Should lint as `f` would be consumed anyway + let f = S { f: String::from("foo") }; + let g = &S { ..f }; + + // Should lint: the result of an expression is mutable + let h = &mut S { + ..*Box::new(S { f: String::from("foo") }) + }; + + // Should not lint: `m` would be both alive and borrowed + let m = T { f: 17 }; + let n = &T { ..m }; + + // Should not lint: `m` should not be modified + let o = &mut T { ..m }; + o.f = 32; + assert_eq!(m.f, 17); + + // Should not lint: `m` should not be modified + let o = &mut T { ..m } as *mut T; + unsafe { &mut *o }.f = 32; + assert_eq!(m.f, 17); + + // Should lint: the result of an expression is mutable and temporary + let p = &mut T { + ..*Box::new(T { f: 5 }) + }; +} diff --git a/tests/ui/unnecessary_struct_initialization.stderr b/tests/ui/unnecessary_struct_initialization.stderr new file mode 100644 index 00000000000..ca497057702 --- /dev/null +++ b/tests/ui/unnecessary_struct_initialization.stderr @@ -0,0 +1,46 @@ +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:34:9 + | +LL | Self { ..*self } + | ^^^^^^^^^^^^^^^^ help: replace with: `*self` + | + = note: `-D clippy::unnecessary-struct-initialization` implied by `-D warnings` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:41:17 + | +LL | let mut b = S { ..a }; + | ^^^^^^^^^ help: replace with: `a` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:44:18 + | +LL | let c = &mut S { ..b }; + | ^^^^^^^^^ help: replace with: `b` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:52:14 + | +LL | let g = &S { ..f }; + | ^^^^^^^^^ help: replace with: `f` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:55:18 + | +LL | let h = &mut S { + | __________________^ +LL | | ..*Box::new(S { f: String::from("foo") }) +LL | | }; + | |_____^ help: replace with: `*Box::new(S { f: String::from("foo") })` + +error: unnecessary struct building + --> $DIR/unnecessary_struct_initialization.rs:74:18 + | +LL | let p = &mut T { + | __________________^ +LL | | ..*Box::new(T { f: 5 }) +LL | | }; + | |_____^ help: replace with: `*Box::new(T { f: 5 })` + +error: aborting due to 6 previous errors +