Merge branch 'rust-lang:master' into clear-with-drain

This commit is contained in:
bluthej 2023-03-26 19:11:38 +02:00 committed by GitHub
commit 1d168b31c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 715 additions and 321 deletions

View file

@ -11,3 +11,6 @@ target-dir = "target"
[unstable] [unstable]
binary-dep-depinfo = true binary-dep-depinfo = true
[profile.dev]
split-debuginfo = "unpacked"

View file

@ -180,6 +180,8 @@ jobs:
# Run # Run
- name: Build Integration Test - name: Build Integration Test
env:
CARGO_PROFILE_DEV_SPLIT_DEBUGINFO: off
run: cargo test --test integration --features integration --no-run run: cargo test --test integration --features integration --no-run
# Upload # Upload

View file

@ -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_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_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_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_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_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 [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps

View file

@ -1,3 +1,5 @@
// REUSE-IgnoreStart
Copyright 2014-2022 The Rust Project Developers Copyright 2014-2022 The Rust Project Developers
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
@ -5,3 +7,5 @@ http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
option. All files in the project carrying such notice may not be option. All files in the project carrying such notice may not be
copied, modified, or distributed except according to those terms. copied, modified, or distributed except according to those terms.
// REUSE-IgnoreEnd

View file

@ -275,6 +275,8 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
## License ## License
<!-- REUSE-IgnoreStart -->
Copyright 2014-2022 The Rust Project Developers Copyright 2014-2022 The Rust Project Developers
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
@ -282,3 +284,5 @@ Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
<LICENSE-MIT or [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)>, at your <LICENSE-MIT or [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)>, at your
option. Files in the project may not be option. Files in the project may not be
copied, modified, or distributed except according to those terms. copied, modified, or distributed except according to those terms.
<!-- REUSE-IgnoreEnd -->

View file

@ -18,6 +18,7 @@ because that's clearly a non-descriptive name.
- [Cargo lints](#cargo-lints) - [Cargo lints](#cargo-lints)
- [Rustfix tests](#rustfix-tests) - [Rustfix tests](#rustfix-tests)
- [Testing manually](#testing-manually) - [Testing manually](#testing-manually)
- [Running directly](#running-directly)
- [Lint declaration](#lint-declaration) - [Lint declaration](#lint-declaration)
- [Lint registration](#lint-registration) - [Lint registration](#lint-registration)
- [Lint passes](#lint-passes) - [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 from the working copy root. With tests in place, let's have a look at
implementing our lint now. 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 ## Lint declaration
Let's start by opening the new file created in the `clippy_lints` crate at Let's start by opening the new file created in the `clippy_lints` crate at

View file

@ -495,18 +495,19 @@ struct NotSimplificationVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind { if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind &&
if let Some(suggestion) = simplify_not(self.cx, inner) { !inner.span.from_expansion() &&
span_lint_and_sugg( let Some(suggestion) = simplify_not(self.cx, inner)
self.cx, {
NONMINIMAL_BOOL, span_lint_and_sugg(
expr.span, self.cx,
"this boolean expression can be simplified", NONMINIMAL_BOOL,
"try", expr.span,
suggestion, "this boolean expression can be simplified",
Applicability::MachineApplicable, "try",
); suggestion,
} Applicability::MachineApplicable,
);
} }
walk_expr(self, expr); walk_expr(self, expr);

View file

@ -2,8 +2,9 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::expr_or_init; use clippy_utils::expr_or_init;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; 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::def::{DefKind, Res};
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -163,19 +164,34 @@ pub(super) fn check(
_ => return, _ => 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| { 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.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...");
diag.span_suggestion_with_style( if !cast_from.is_floating_point() {
expr.span, offer_suggestion(cx, expr, cast_expr, cast_to_span, diag);
"... or use `try_from` and handle the error accordingly", }
suggestion,
Applicability::Unspecified,
// always show the suggestion in a separate line
SuggestionStyle::ShowAlways,
);
}); });
} }
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,
);
}

View file

@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
span: Span, span: Span,
def_id: LocalDefId, 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) { let expr = if is_async_fn(kind) {
match get_async_fn_body(cx.tcx, body) { match get_async_fn_body(cx.tcx, body) {
Some(b) => b, Some(b) => b,

View file

@ -619,6 +619,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO, crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO, crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO, crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO,
crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO, crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO, crate::unnested_or_patterns::UNNESTED_OR_PATTERNS_INFO,
crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO, crate::unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME_INFO,

View file

@ -181,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
self_ty, self_ty,
.. ..
}) = item.kind; }) = 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 !item.span.from_expansion();
if let Some(def_id) = trait_ref.trait_def_id(); if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Default, def_id); if cx.tcx.is_diagnostic_item(sym::Default, def_id);

View file

@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}) = item.kind }) = item.kind
{ {
let ty = cx.tcx.type_of(item.owner_id).subst_identity(); 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_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);

View file

@ -32,7 +32,7 @@ declare_clippy_lint! {
/// ### Example /// ### Example
/// ```rust /// ```rust
/// // Assuming that `clippy.toml` contains the following line: /// // Assuming that `clippy.toml` contains the following line:
/// // allowed-locales = ["Latin", "Cyrillic"] /// // allowed-scripts = ["Latin", "Cyrillic"]
/// let counter = 10; // OK, latin is allowed. /// let counter = 10; // OK, latin is allowed.
/// let счётчик = 10; // OK, cyrillic is allowed. /// let счётчик = 10; // OK, cyrillic is allowed.
/// let zähler = 10; // OK, it's still latin. /// let zähler = 10; // OK, it's still latin.

View file

@ -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<'_>) { pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id()); 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 { 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 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 fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
if let Some(attr) = attr { if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, 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( check_must_use_candidate(
cx, cx,
sig.decl, 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 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 fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id()); 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 { if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr);
} else if is_public } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
&& !is_proc_macro(cx.sess(), attrs)
&& trait_ref_of_method(cx, item.owner_id.def_id).is_none()
{
check_must_use_candidate( check_must_use_candidate(
cx, cx,
sig.decl, 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 fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id()); 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 { if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, 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 { } else if let hir::TraitFn::Provided(eid) = *eid {
let body = cx.tcx.hir().body(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( check_must_use_candidate(
cx, cx,
sig.decl, sig.decl,

View file

@ -9,7 +9,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; 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! { declare_clippy_lint! {
/// ### What it does /// ### 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 send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span(); let span = decl.output.span();
let infcx = cx.tcx.infer_ctxt().build(); let infcx = cx.tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);
let cause = traits::ObligationCause::misc(span, fn_def_id); 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() { if !send_errors.is_empty() {
span_lint_and_then( span_lint_and_then(
cx, cx,

View file

@ -167,7 +167,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
Finite Finite
}, },
ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), 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, _) => { ExprKind::Call(path, _) => {
if let ExprKind::Path(ref qpath) = path.kind { if let ExprKind::Path(ref qpath) = path.kind {
cx.qpath_res(qpath, path.hir_id) cx.qpath_res(qpath, path.hir_id)

View file

@ -302,6 +302,7 @@ mod unit_types;
mod unnamed_address; mod unnamed_address;
mod unnecessary_owned_empty_strings; mod unnecessary_owned_empty_strings;
mod unnecessary_self_imports; mod unnecessary_self_imports;
mod unnecessary_struct_initialization;
mod unnecessary_wraps; mod unnecessary_wraps;
mod unnested_or_patterns; mod unnested_or_patterns;
mod unsafe_removed_from_name; 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(let_with_type_underscore::UnderscoreTyped));
store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); 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(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` // add lints here, do not remove this comment, it's used in `new_lint`
} }

View file

@ -124,8 +124,7 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult { fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
match expr.kind { match expr.kind {
ExprKind::Box(e) ExprKind::Unary(_, e)
| ExprKind::Unary(_, e)
| ExprKind::Cast(e, _) | ExprKind::Cast(e, _)
| ExprKind::Type(e, _) | ExprKind::Type(e, _)
| ExprKind::Field(e, _) | ExprKind::Field(e, _)

View file

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_then; 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 clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; 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>> { fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
if_chain! { if_chain! {
if let Some(block_expr) = block.expr; 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 { if let Expr {
kind: ExprKind::Closure(&Closure { body, .. }), kind: ExprKind::Closure(&Closure { body, .. }),
.. ..
} = args[0]; } = block_expr;
let closure_body = cx.tcx.hir().body(body); let closure_body = cx.tcx.hir().body(body);
if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block)); if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
then { then {

View file

@ -321,7 +321,6 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
self.has_significant_drop = true; self.has_significant_drop = true;
} }
} }
ExprKind::Box(..) |
ExprKind::Array(..) | ExprKind::Array(..) |
ExprKind::Call(..) | ExprKind::Call(..) |
ExprKind::Unary(..) | ExprKind::Unary(..) |

View file

@ -33,10 +33,6 @@ struct SortByKeyDetection {
/// contains a and the other replaces it with b) /// 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 { fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool {
match (&a_expr.kind, &b_expr.kind) { 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 // Two arrays with mirrored contents
(ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { (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)) iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))

View file

@ -369,10 +369,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
Node::Item(item) => { Node::Item(item) => {
if let ItemKind::Fn(_, _, body_id) = &item.kind if let ItemKind::Fn(_, _, body_id) = &item.kind
&& let output_ty = return_ty(cx, item.owner_id) && let output_ty = return_ty(cx, item.owner_id)
&& Inherited::build(cx.tcx, item.owner_id.def_id).enter(|inherited| { && 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); && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id)
fn_ctxt.can_coerce(ty, output_ty) && fn_ctxt.can_coerce(ty, output_ty)
}) { {
if has_lifetime(output_ty) && has_lifetime(ty) { if has_lifetime(output_ty) && has_lifetime(ty) {
return false; return false;
} }

View file

@ -127,8 +127,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
| ExprKind::Type(inner, _) | ExprKind::Type(inner, _)
| ExprKind::Unary(_, inner) | ExprKind::Unary(_, inner)
| ExprKind::Field(inner, _) | ExprKind::Field(inner, _)
| ExprKind::AddrOf(_, _, inner) | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner),
| ExprKind::Box(inner) => has_no_effect(cx, inner),
ExprKind::Struct(_, fields, ref base) => { ExprKind::Struct(_, fields, ref base) => {
!has_drop(cx, cx.typeck_results().expr_ty(expr)) !has_drop(cx, cx.typeck_results().expr_ty(expr))
&& fields.iter().all(|field| has_no_effect(cx, field.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<Vec
| ExprKind::Type(inner, _) | ExprKind::Type(inner, _)
| ExprKind::Unary(_, inner) | ExprKind::Unary(_, inner)
| ExprKind::Field(inner, _) | ExprKind::Field(inner, _)
| ExprKind::AddrOf(_, _, inner) | ExprKind::AddrOf(_, _, inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
| ExprKind::Box(inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
ExprKind::Struct(_, fields, ref base) => { ExprKind::Struct(_, fields, ref base) => {
if has_drop(cx, cx.typeck_results().expr_ty(expr)) { if has_drop(cx, cx.typeck_results().expr_ty(expr)) {
None None

View file

@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if_chain! { if_chain! {
if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; 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 let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.res.def_id() == eq_trait; if trait_ref.path.res.def_id() == eq_trait;
then { then {

View file

@ -213,8 +213,7 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_
} }
loop { loop {
expr = match expr.kind { expr = match expr.kind {
ExprKind::Box(e) ExprKind::AddrOf(_, _, e)
| ExprKind::AddrOf(_, _, e)
| ExprKind::Block( | ExprKind::Block(
&Block { &Block {
stmts: [], stmts: [],

View file

@ -1,9 +1,9 @@
use crate::FxHashSet;
use clippy_utils::{ use clippy_utils::{
diagnostics::span_lint_and_then, diagnostics::span_lint_and_then,
get_attr, get_attr,
source::{indent_of, snippet}, source::{indent_of, snippet},
}; };
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, Diagnostic}; use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::{ use rustc_hir::{
self as hir, self as hir,
@ -58,6 +58,7 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]);
pub struct SignificantDropTightening<'tcx> { pub struct SignificantDropTightening<'tcx> {
/// Auxiliary structure used to avoid having to verify the same type multiple times. /// Auxiliary structure used to avoid having to verify the same type multiple times.
seen_types: FxHashSet<Ty<'tcx>>, seen_types: FxHashSet<Ty<'tcx>>,
type_cache: FxHashMap<Ty<'tcx>, bool>,
} }
impl<'tcx> SignificantDropTightening<'tcx> { impl<'tcx> SignificantDropTightening<'tcx> {
@ -118,7 +119,7 @@ impl<'tcx> SignificantDropTightening<'tcx> {
stmt: &hir::Stmt<'_>, stmt: &hir::Stmt<'_>,
cb: impl Fn(&mut SigDropAuxParams), 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); sig_drop_finder.visit_expr(expr);
if sig_drop_finder.has_sig_drop { if sig_drop_finder.has_sig_drop {
cb(sdap); cb(sdap);
@ -296,15 +297,24 @@ impl Default for SigDropAuxParams {
struct SigDropChecker<'cx, 'sdt, 'tcx> { struct SigDropChecker<'cx, 'sdt, 'tcx> {
cx: &'cx LateContext<'tcx>, cx: &'cx LateContext<'tcx>,
seen_types: &'sdt mut FxHashSet<Ty<'tcx>>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
} }
impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
pub(crate) fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self { pub(crate) fn new(
cx: &'cx LateContext<'tcx>,
seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
) -> Self {
seen_types.clear(); 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() { if let Some(adt) = ty.ty_adt_def() {
let mut iter = get_attr( let mut iter = get_attr(
self.cx.sess(), 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 { fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool {
!self.seen_types.insert(ty) !self.seen_types.insert(ty)
} }
@ -353,11 +373,15 @@ struct SigDropFinder<'cx, 'sdt, 'tcx> {
} }
impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> {
fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet<Ty<'tcx>>) -> Self { fn new(
cx: &'cx LateContext<'tcx>,
seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
) -> Self {
Self { Self {
cx, cx,
has_sig_drop: false, 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::Assign(..)
| hir::ExprKind::AssignOp(..) | hir::ExprKind::AssignOp(..)
| hir::ExprKind::Binary(..) | hir::ExprKind::Binary(..)
| hir::ExprKind::Box(..)
| hir::ExprKind::Call(..) | hir::ExprKind::Call(..)
| hir::ExprKind::Field(..) | hir::ExprKind::Field(..)
| hir::ExprKind::If(..) | hir::ExprKind::If(..)

View file

@ -596,8 +596,7 @@ fn ident_difference_expr_with_base_location(
| (MethodCall(_), MethodCall(_)) | (MethodCall(_), MethodCall(_))
| (Call(_, _), Call(_, _)) | (Call(_, _), Call(_, _))
| (ConstBlock(_), ConstBlock(_)) | (ConstBlock(_), ConstBlock(_))
| (Array(_), Array(_)) | (Array(_), Array(_)) => {
| (Box(_), Box(_)) => {
// keep going // keep going
}, },
_ => { _ => {

View file

@ -2,8 +2,9 @@ use super::utils::check_cast;
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_ast::ExprPrecedence;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Expr; use rustc_hir::{Expr, Node};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_middle::ty::{cast::CastKind, Ty};
@ -19,7 +20,7 @@ pub(super) fn check<'tcx>(
) -> bool { ) -> bool {
use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
let mut app = Applicability::MachineApplicable; 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) => { Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
.as_ty(to_ty.to_string()) .as_ty(to_ty.to_string())
@ -39,6 +40,12 @@ pub(super) fn check<'tcx>(
_ => return false, _ => 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( span_lint_and_sugg(
cx, cx,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,

View file

@ -33,38 +33,37 @@ pub(super) fn check_cast<'tcx>(
let hir_id = e.hir_id; let hir_id = e.hir_id;
let local_def_id = hir_id.owner.def_id; let local_def_id = hir_id.owner.def_id;
Inherited::build(cx.tcx, local_def_id).enter(|inherited| { let inherited = Inherited::new(cx.tcx, local_def_id);
let fn_ctxt = FnCtxt::new(inherited, cx.param_env, 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!( assert!(
!fn_ctxt.errors_reported_since_creation(), !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( res.ok()
&fn_ctxt, } else {
e, None
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
}
})
} }

View file

@ -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
}
}

View file

@ -395,11 +395,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
} }
self.expr(field!(let_expr.init)); self.expr(field!(let_expr.init));
}, },
ExprKind::Box(inner) => {
bind!(self, inner);
kind!("Box({inner})");
self.expr(inner);
},
ExprKind::Array(elements) => { ExprKind::Array(elements) => {
bind!(self, elements); bind!(self, elements);
kind!("Array({elements})"); kind!("Array({elements})");

View file

@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Paren(l), _) => eq_expr(l, r), (Paren(l), _) => eq_expr(l, r),
(_, Paren(r)) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r),
(Err, Err) => true, (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)), (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)), (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), (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),

View file

@ -145,8 +145,8 @@ pub fn get_unique_attr<'a>(
/// Return true if the attributes contain any of `proc_macro`, /// Return true if the attributes contain any of `proc_macro`,
/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool {
attrs.iter().any(|attr| sess.is_proc_macro_attr(attr)) attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr)
} }
/// Return true if the attributes contain `#[doc(hidden)]` /// Return true if the attributes contain `#[doc(hidden)]`

View file

@ -112,7 +112,6 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
/// Get the search patterns to use for the given expression /// Get the search patterns to use for the given expression
fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
match e.kind { match e.kind {
ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1),
ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),

View file

@ -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 // Memory allocation, custom operator, loop, or call to an unknown function
ExprKind::Box(_) ExprKind::Unary(..) | ExprKind::Binary(..) | ExprKind::Loop(..) | ExprKind::Call(..) => {
| ExprKind::Unary(..) self.eagerness = Lazy;
| ExprKind::Binary(..) },
| ExprKind::Loop(..)
| ExprKind::Call(..) => self.eagerness = Lazy,
ExprKind::ConstBlock(_) ExprKind::ConstBlock(_)
| ExprKind::Array(_) | ExprKind::Array(_)

View file

@ -249,7 +249,6 @@ impl HirEqInterExpr<'_, '_, '_> {
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
&& both(le, re, |l, r| self.eq_expr(l, r)) && 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)) => { (&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) 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); self.hash_expr(j);
} }
}, },
ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
self.hash_expr(e); self.hash_expr(e);
}, },
ExprKind::Call(fun, args) => { ExprKind::Call(fun, args) => {

View file

@ -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, /// 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>> { pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call( if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind {
_,
&[
Expr {
kind: ExprKind::Closure(&Closure { body, .. }),
..
},
],
) = body.value.kind
{
if let ExprKind::Block( if let ExprKind::Block(
Block { Block {
stmts: [], stmts: [],

View file

@ -533,6 +533,14 @@ struct FormatArgsValues<'tcx> {
} }
impl<'tcx> 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 { fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
let mut pos_to_value_index = Vec::new(); let mut pos_to_value_index = Vec::new();
let mut value_args = 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))?; .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;
let newline = macro_name == 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(pieces, args)
// ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) // ::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 ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
&& let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.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)?; let format_string = FormatString::new(cx, pieces)?;
@ -1026,7 +1035,7 @@ impl<'tcx> FormatArgsExpn<'tcx> {
return None; 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 // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse
// them. // 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) let args = izip!(positions, parsed_args, parser.arg_places)
.map(|(position, parsed_arg, arg_span)| { .map(|(position, parsed_arg, arg_span)| {

View file

@ -37,7 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
| ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, | 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::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"), ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"), ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
@ -176,6 +176,10 @@ fn check_rvalue<'tcx>(
// FIXME(dyn-star) // FIXME(dyn-star)
unimplemented!() 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 // binops are fine on integers
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
check_operand(tcx, lhs, span, body)?; check_operand(tcx, lhs, span, body)?;
@ -241,6 +245,7 @@ fn check_statement<'tcx>(
| StatementKind::StorageDead(_) | StatementKind::StorageDead(_)
| StatementKind::Retag { .. } | StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..) | StatementKind::AscribeUserType(..)
| StatementKind::PlaceMention(..)
| StatementKind::Coverage(..) | StatementKind::Coverage(..)
| StatementKind::ConstEvalCounter | StatementKind::ConstEvalCounter
| StatementKind::Nop => Ok(()), | StatementKind::Nop => Ok(()),

View file

@ -125,7 +125,6 @@ impl<'a> Sugg<'a> {
match expr.kind { match expr.kind {
hir::ExprKind::AddrOf(..) hir::ExprKind::AddrOf(..)
| hir::ExprKind::Box(..)
| hir::ExprKind::If(..) | hir::ExprKind::If(..)
| hir::ExprKind::Let(..) | hir::ExprKind::Let(..)
| hir::ExprKind::Closure { .. } | hir::ExprKind::Closure { .. }
@ -180,7 +179,6 @@ impl<'a> Sugg<'a> {
match expr.kind { match expr.kind {
_ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), _ if expr.span.ctxt() != ctxt => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0),
ast::ExprKind::AddrOf(..) ast::ExprKind::AddrOf(..)
| ast::ExprKind::Box(..)
| ast::ExprKind::Closure { .. } | ast::ExprKind::Closure { .. }
| ast::ExprKind::If(..) | ast::ExprKind::If(..)
| ast::ExprKind::Let(..) | ast::ExprKind::Let(..)

View file

@ -599,10 +599,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
| ExprKind::Let(&Let { init: e, .. }) => { | ExprKind::Let(&Let { init: e, .. }) => {
helper(typeck, false, e, f)?; helper(typeck, false, e, f)?;
}, },
ExprKind::Block(&Block { expr: Some(e), .. }, _) ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => {
| ExprKind::Box(e)
| ExprKind::Cast(e, _)
| ExprKind::Unary(_, e) => {
helper(typeck, true, e, f)?; helper(typeck, true, e, f)?;
}, },
ExprKind::Call(callee, args) => { ExprKind::Call(callee, args) => {

View file

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2023-03-10" channel = "nightly-2023-03-24"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]

View file

@ -49,6 +49,8 @@ The changelog for `rustc_tools_util` is available under:
## License ## License
<!-- REUSE-IgnoreStart -->
Copyright 2014-2022 The Rust Project Developers Copyright 2014-2022 The Rust Project Developers
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
@ -56,3 +58,5 @@ http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
option. All files in the project carrying such notice may not be option. All files in the project carrying such notice may not be
copied, modified, or distributed except according to those terms. copied, modified, or distributed except according to those terms.
<!-- REUSE-IgnoreEnd -->

View file

@ -9,3 +9,4 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy
note: Clippy version: foo note: Clippy version: foo
thread panicked while panicking. aborting.

View file

@ -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 if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind
&& let FnRetTy::DefaultReturn(_) = fn_decl.output && let FnRetTy::DefaultReturn(_) = fn_decl.output
&& expr1 = &cx.tcx.hir().body(body_id).value && expr1 = &cx.tcx.hir().body(body_id).value
&& let ExprKind::Call(func, args) = expr1.kind && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = 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 FnRetTy::DefaultReturn(_) = fn_decl1.output && let FnRetTy::DefaultReturn(_) = fn_decl1.output
&& expr2 = &cx.tcx.hir().body(body_id1).value && expr2 = &cx.tcx.hir().body(body_id1).value
&& let ExprKind::Block(block, None) = expr2.kind && let ExprKind::Block(block, None) = expr2.kind

View file

@ -1,4 +1,3 @@
#![feature(box_syntax)]
#![feature(lint_reasons)] #![feature(lint_reasons)]
#![allow( #![allow(
clippy::borrowed_box, clippy::borrowed_box,
@ -34,7 +33,7 @@ fn ok_box_trait(boxed_trait: &Box<dyn Z>) {
} }
fn warn_call() { fn warn_call() {
let x = box A; let x = Box::new(A);
x.foo(); x.foo();
} }
@ -43,41 +42,41 @@ fn warn_arg(x: Box<A>) {
} }
fn nowarn_closure_arg() { fn nowarn_closure_arg() {
let x = Some(box A); let x = Some(Box::new(A));
x.map_or((), |x| take_ref(&x)); x.map_or((), |x| take_ref(&x));
} }
fn warn_rename_call() { fn warn_rename_call() {
let x = box A; let x = Box::new(A);
let y = x; let y = x;
y.foo(); // via autoderef y.foo(); // via autoderef
} }
fn warn_notuse() { fn warn_notuse() {
let bz = box A; let bz = Box::new(A);
} }
fn warn_pass() { fn warn_pass() {
let bz = box A; let bz = Box::new(A);
take_ref(&bz); // via deref coercion take_ref(&bz); // via deref coercion
} }
fn nowarn_return() -> Box<A> { fn nowarn_return() -> Box<A> {
box A // moved out, "escapes" Box::new(A) // moved out, "escapes"
} }
fn nowarn_move() { fn nowarn_move() {
let bx = box A; let bx = Box::new(A);
drop(bx) // moved in, "escapes" drop(bx) // moved in, "escapes"
} }
fn nowarn_call() { fn nowarn_call() {
let bx = box A; let bx = Box::new(A);
bx.clone(); // method only available to Box, not via autoderef bx.clone(); // method only available to Box, not via autoderef
} }
fn nowarn_pass() { fn nowarn_pass() {
let bx = box A; let bx = Box::new(A);
take_box(&bx); // fn needs &Box take_box(&bx); // fn needs &Box
} }
@ -86,30 +85,20 @@ fn take_ref(x: &A) {}
fn nowarn_ref_take() { fn nowarn_ref_take() {
// false positive, should actually warn // false positive, should actually warn
let x = box A; let x = Box::new(A);
let y = &x; let y = &x;
take_box(y); take_box(y);
} }
fn nowarn_match() { fn nowarn_match() {
let x = box A; // moved into a match let x = Box::new(A); // moved into a match
match x { match x {
y => drop(y), y => drop(y),
} }
} }
fn warn_match() { fn warn_match() {
let x = box A; let x = Box::new(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];
match &x { match &x {
// not moved // not moved
y => (), y => (),

View file

@ -1,5 +1,5 @@
error: local variable doesn't need to be boxed here 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<A>) { LL | fn warn_arg(x: Box<A>) {
| ^ | ^
@ -7,19 +7,19 @@ LL | fn warn_arg(x: Box<A>) {
= note: `-D clippy::boxed-local` implied by `-D warnings` = note: `-D clippy::boxed-local` implied by `-D warnings`
error: local variable doesn't need to be boxed here 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<PeekableSeekable<&()>>) -> () {} LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: local variable doesn't need to be boxed here 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<Self>, x: Box<u32>) -> u32 { LL | fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
| ^ | ^
error: local variable doesn't need to be boxed here 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<u32>) {} LL | fn foo(x: Box<u32>) {}
| ^ | ^

View file

@ -29,6 +29,12 @@ fn main() {
1f64 as isize; 1f64 as isize;
1f64 as usize; 1f64 as usize;
1f32 as u32 as u16; 1f32 as u32 as u16;
{
let _x: i8 = 1i32 as _;
1f32 as i32;
1f64 as i32;
1f32 as u8;
}
// Test clippy::cast_possible_wrap // Test clippy::cast_possible_wrap
1u8 as i8; 1u8 as i8;
1u16 as i16; 1u16 as i16;

View file

@ -44,10 +44,6 @@ LL | 1f32 as i32;
| |
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings` = 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 error: casting `f32` to `u32` may truncate the value
--> $DIR/cast.rs:25:5 --> $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: 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 error: casting `f32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:25:5 --> $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: 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 error: casting `i32` to `i8` may truncate the value
--> $DIR/cast.rs:27:5 --> $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: 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 error: casting `f64` to `usize` may truncate the value
--> $DIR/cast.rs:30:5 --> $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: 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 error: casting `f64` to `usize` may lose the sign of the value
--> $DIR/cast.rs:30:5 --> $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: 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 error: casting `f32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:31:5 --> $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; 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 error: casting `u8` to `i8` may wrap around the value
--> $DIR/cast.rs:33:5 --> $DIR/cast.rs:39:5
| |
LL | 1u8 as i8; LL | 1u8 as i8;
| ^^^^^^^^^ | ^^^^^^^^^
@ -174,43 +192,43 @@ LL | 1u8 as i8;
= note: `-D clippy::cast-possible-wrap` implied by `-D warnings` = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
error: casting `u16` to `i16` may wrap around the value error: casting `u16` to `i16` may wrap around the value
--> $DIR/cast.rs:34:5 --> $DIR/cast.rs:40:5
| |
LL | 1u16 as i16; LL | 1u16 as i16;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: casting `u32` to `i32` may wrap around the value error: casting `u32` to `i32` may wrap around the value
--> $DIR/cast.rs:35:5 --> $DIR/cast.rs:41:5
| |
LL | 1u32 as i32; LL | 1u32 as i32;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: casting `u64` to `i64` may wrap around the value error: casting `u64` to `i64` may wrap around the value
--> $DIR/cast.rs:36:5 --> $DIR/cast.rs:42:5
| |
LL | 1u64 as i64; LL | 1u64 as i64;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: casting `usize` to `isize` may wrap around the value error: casting `usize` to `isize` may wrap around the value
--> $DIR/cast.rs:37:5 --> $DIR/cast.rs:43:5
| |
LL | 1usize as isize; LL | 1usize as isize;
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value 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; LL | -1i32 as u32;
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
error: casting `isize` to `usize` may lose the sign of the value 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; LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
error: casting `i64` to `i8` may truncate the value 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 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 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 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 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; 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 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; 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` = note: `-D clippy::cast-enum-truncation` implied by `-D warnings`
error: casting `main::E5` to `i8` may truncate the value 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; 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 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; LL | let _ = Self::A as i8;
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: casting `main::E6` to `i16` may truncate the value 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; 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 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; 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 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; LL | let _ = self as u16;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -308,7 +326,7 @@ LL | let _ = u16::try_from(self);
| ~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~
error: casting `u32` to `u8` may truncate the value 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; 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: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
help: ... or use `try_from` and handle the error accordingly 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 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; 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: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
help: ... or use `try_from` and handle the error accordingly 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

View file

@ -31,9 +31,7 @@ impl core::ops::Mul<i32> for Vec1 {
#[allow(clippy::no_effect)] #[allow(clippy::no_effect)]
#[warn(clippy::erasing_op)] #[warn(clippy::erasing_op)]
fn main() { fn test(x: u8) {
let x: u8 = 0;
x * 0; x * 0;
0 & x; 0 & x;
0 / x; 0 / x;
@ -41,3 +39,7 @@ fn main() {
0 * Vec1 { x: 5 }; 0 * Vec1 { x: 5 };
Vec1 { x: 5 } * 0; Vec1 { x: 5 } * 0;
} }
fn main() {
test(0)
}

View file

@ -1,5 +1,5 @@
error: this operation will always return zero. This is likely not the intended outcome 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; LL | x * 0;
| ^^^^^ | ^^^^^
@ -7,25 +7,25 @@ LL | x * 0;
= note: `-D clippy::erasing-op` implied by `-D warnings` = note: `-D clippy::erasing-op` implied by `-D warnings`
error: this operation will always return zero. This is likely not the intended outcome 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; LL | 0 & x;
| ^^^^^ | ^^^^^
error: this operation will always return zero. This is likely not the intended outcome 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; LL | 0 / x;
| ^^^^^ | ^^^^^
error: this operation will always return zero. This is likely not the intended outcome 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 }; LL | 0 * Vec1 { x: 5 };
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: this operation will always return zero. This is likely not the intended outcome 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; LL | Vec1 { x: 5 } * 0;
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^

View file

@ -4,7 +4,7 @@
#[rustfmt::skip] #[rustfmt::skip]
fn main() { fn main() {
let mut i = 1i32; let mut i = 1i32;
let mut var1 = 0i32; let mut var1 = 13i32;
let mut var2 = -1i32; let mut var2 = -1i32;
1 + i; 1 + i;
i * 2; i * 2;

View file

@ -1,5 +1,5 @@
#![warn(clippy::needless_update)] #![warn(clippy::needless_update)]
#![allow(clippy::no_effect)] #![allow(clippy::no_effect, clippy::unnecessary_struct_initialization)]
struct S { struct S {
pub a: i32, pub a: i32,

View file

@ -1,7 +1,12 @@
#![feature(box_syntax, fn_traits, unboxed_closures)] #![feature(fn_traits, unboxed_closures)]
#![warn(clippy::no_effect_underscore_binding)] #![warn(clippy::no_effect_underscore_binding)]
#![allow(dead_code, path_statements)] #![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 Unit;
struct Tuple(i32); struct Tuple(i32);
@ -102,7 +107,6 @@ fn main() {
*&42; *&42;
&6; &6;
(5, 6, 7); (5, 6, 7);
box 42;
..; ..;
5..; 5..;
..5; ..5;

View file

@ -1,5 +1,5 @@
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:92:5 --> $DIR/no_effect.rs:97:5
| |
LL | 0; LL | 0;
| ^^ | ^^
@ -7,157 +7,151 @@ LL | 0;
= note: `-D clippy::no-effect` implied by `-D warnings` = note: `-D clippy::no-effect` implied by `-D warnings`
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:93:5 --> $DIR/no_effect.rs:98:5
| |
LL | s2; LL | s2;
| ^^^ | ^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:94:5 --> $DIR/no_effect.rs:99:5
| |
LL | Unit; LL | Unit;
| ^^^^^ | ^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:95:5 --> $DIR/no_effect.rs:100:5
| |
LL | Tuple(0); LL | Tuple(0);
| ^^^^^^^^^ | ^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:96:5 --> $DIR/no_effect.rs:101:5
| |
LL | Struct { field: 0 }; LL | Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:97:5 --> $DIR/no_effect.rs:102:5
| |
LL | Struct { ..s }; LL | Struct { ..s };
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:98:5 --> $DIR/no_effect.rs:103:5
| |
LL | Union { a: 0 }; LL | Union { a: 0 };
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:99:5 --> $DIR/no_effect.rs:104:5
| |
LL | Enum::Tuple(0); LL | Enum::Tuple(0);
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:100:5 --> $DIR/no_effect.rs:105:5
| |
LL | Enum::Struct { field: 0 }; LL | Enum::Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:101:5 --> $DIR/no_effect.rs:106:5
| |
LL | 5 + 6; LL | 5 + 6;
| ^^^^^^ | ^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:102:5 --> $DIR/no_effect.rs:107:5
| |
LL | *&42; LL | *&42;
| ^^^^^ | ^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:103:5 --> $DIR/no_effect.rs:108:5
| |
LL | &6; LL | &6;
| ^^^ | ^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:104:5 --> $DIR/no_effect.rs:109:5
| |
LL | (5, 6, 7); LL | (5, 6, 7);
| ^^^^^^^^^^ | ^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:105:5 --> $DIR/no_effect.rs:110:5
|
LL | box 42;
| ^^^^^^^
error: statement with no effect
--> $DIR/no_effect.rs:106:5
| |
LL | ..; LL | ..;
| ^^^ | ^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:107:5 --> $DIR/no_effect.rs:111:5
| |
LL | 5..; LL | 5..;
| ^^^^ | ^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:108:5 --> $DIR/no_effect.rs:112:5
| |
LL | ..5; LL | ..5;
| ^^^^ | ^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:109:5 --> $DIR/no_effect.rs:113:5
| |
LL | 5..6; LL | 5..6;
| ^^^^^ | ^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:110:5 --> $DIR/no_effect.rs:114:5
| |
LL | 5..=6; LL | 5..=6;
| ^^^^^^ | ^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:111:5 --> $DIR/no_effect.rs:115:5
| |
LL | [42, 55]; LL | [42, 55];
| ^^^^^^^^^ | ^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:112:5 --> $DIR/no_effect.rs:116:5
| |
LL | [42, 55][1]; LL | [42, 55][1];
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:113:5 --> $DIR/no_effect.rs:117:5
| |
LL | (42, 55).1; LL | (42, 55).1;
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:114:5 --> $DIR/no_effect.rs:118:5
| |
LL | [42; 55]; LL | [42; 55];
| ^^^^^^^^^ | ^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:115:5 --> $DIR/no_effect.rs:119:5
| |
LL | [42; 55][13]; LL | [42; 55][13];
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:117:5 --> $DIR/no_effect.rs:121:5
| |
LL | || x += 5; LL | || x += 5;
| ^^^^^^^^^^ | ^^^^^^^^^^
error: statement with no effect error: statement with no effect
--> $DIR/no_effect.rs:119:5 --> $DIR/no_effect.rs:123:5
| |
LL | FooString { s: s }; LL | FooString { s: s };
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect 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; LL | let _unused = 1;
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -165,22 +159,22 @@ LL | let _unused = 1;
= note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings`
error: binding to `_` prefixed variable with no side-effect 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"); LL | let _penguin = || println!("Some helpful closure");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect 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 }; LL | let _duck = Struct { field: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: binding to `_` prefixed variable with no side-effect 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]; LL | let _cat = [2, 4, 6, 8][2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 30 previous errors error: aborting due to 29 previous errors

View file

@ -63,3 +63,32 @@ fn issue9428() {
println!("foo"); println!("foo");
} }
} }
fn issue_10523() {
macro_rules! a {
($v:expr) => {
$v.is_some()
};
}
let x: Option<u32> = None;
if !a!(x) {}
}
fn issue_10523_1() {
macro_rules! a {
($v:expr) => {
!$v.is_some()
};
}
let x: Option<u32> = None;
if a!(x) {}
}
fn issue_10523_2() {
macro_rules! a {
() => {
!None::<u32>.is_some()
};
}
if a!() {}
}

View file

@ -1,9 +1,6 @@
#![warn(clippy::overflow_check_conditional)] #![warn(clippy::overflow_check_conditional)]
fn main() { fn test(a: u32, b: u32, c: u32) {
let a: u32 = 1;
let b: u32 = 2;
let c: u32 = 3;
if a + b < a {} if a + b < a {}
if a > a + b {} if a > a + b {}
if a + b < b {} if a + b < b {}
@ -23,3 +20,7 @@ fn main() {
if i > i + j {} if i > i + j {}
if i - j < i {} if i - j < i {}
} }
fn main() {
test(1, 2, 3)
}

View file

@ -1,5 +1,5 @@
error: you are trying to use classic C overflow conditions that will fail in Rust 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 {} LL | if a + b < a {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -7,43 +7,43 @@ LL | if a + b < a {}
= note: `-D clippy::overflow-check-conditional` implied by `-D warnings` = 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 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 {} LL | if a > a + b {}
| ^^^^^^^^^ | ^^^^^^^^^
error: you are trying to use classic C overflow conditions that will fail in Rust 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 {} LL | if a + b < b {}
| ^^^^^^^^^ | ^^^^^^^^^
error: you are trying to use classic C overflow conditions that will fail in Rust 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 {} LL | if b > a + b {}
| ^^^^^^^^^ | ^^^^^^^^^
error: you are trying to use classic C underflow conditions that will fail in Rust 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 {} LL | if a - b > b {}
| ^^^^^^^^^ | ^^^^^^^^^
error: you are trying to use classic C underflow conditions that will fail in Rust 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 {} LL | if b < a - b {}
| ^^^^^^^^^ | ^^^^^^^^^
error: you are trying to use classic C underflow conditions that will fail in Rust 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 {} LL | if a - b > a {}
| ^^^^^^^^^ | ^^^^^^^^^
error: you are trying to use classic C underflow conditions that will fail in Rust 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 {} LL | if a < a - b {}
| ^^^^^^^^^ | ^^^^^^^^^

View file

@ -4,7 +4,7 @@
// would otherwise be responsible for // would otherwise be responsible for
#![warn(clippy::useless_transmute)] #![warn(clippy::useless_transmute)]
#![warn(clippy::transmute_ptr_to_ptr)] #![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}; use std::mem::{size_of, transmute};
@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair {
unsafe { transmute::<Single, Pair>(in_param) } unsafe { transmute::<Single, Pair>(in_param) }
} }
fn issue_10449() {
fn f() {}
let _x: u8 = unsafe { *(f as *const u8) };
}

View file

@ -4,7 +4,7 @@
// would otherwise be responsible for // would otherwise be responsible for
#![warn(clippy::useless_transmute)] #![warn(clippy::useless_transmute)]
#![warn(clippy::transmute_ptr_to_ptr)] #![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}; use std::mem::{size_of, transmute};
@ -77,3 +77,9 @@ fn cannot_be_expressed_as_pointer_cast(in_param: Single) -> Pair {
unsafe { transmute::<Single, Pair>(in_param) } unsafe { transmute::<Single, Pair>(in_param) }
} }
fn issue_10449() {
fn f() {}
let _x: u8 = unsafe { *std::mem::transmute::<fn(), *const u8>(f) };
}

View file

@ -58,5 +58,11 @@ error: transmute from a reference to a pointer
LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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::<fn(), *const u8>(f) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)`
error: aborting due to 10 previous errors

View file

@ -1,7 +1,12 @@
// run-rustfix // run-rustfix
#![feature(box_syntax)] #![allow(
#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] clippy::deref_addrof,
dead_code,
unused,
clippy::no_effect,
clippy::unnecessary_struct_initialization
)]
#![warn(clippy::unnecessary_operation)] #![warn(clippy::unnecessary_operation)]
struct Tuple(i32); struct Tuple(i32);
@ -59,7 +64,6 @@ fn main() {
5;6;get_number(); 5;6;get_number();
get_number(); get_number();
get_number(); get_number();
get_number();
5;get_number(); 5;get_number();
42;get_number(); 42;get_number();
assert!([42, 55].len() > get_usize()); assert!([42, 55].len() > get_usize());

View file

@ -1,7 +1,12 @@
// run-rustfix // run-rustfix
#![feature(box_syntax)] #![allow(
#![allow(clippy::deref_addrof, dead_code, unused, clippy::no_effect)] clippy::deref_addrof,
dead_code,
unused,
clippy::no_effect,
clippy::unnecessary_struct_initialization
)]
#![warn(clippy::unnecessary_operation)] #![warn(clippy::unnecessary_operation)]
struct Tuple(i32); struct Tuple(i32);
@ -57,7 +62,6 @@ fn main() {
*&get_number(); *&get_number();
&get_number(); &get_number();
(5, 6, get_number()); (5, 6, get_number());
box get_number();
get_number()..; get_number()..;
..get_number(); ..get_number();
5..get_number(); 5..get_number();

View file

@ -1,5 +1,5 @@
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:51:5 --> $DIR/unnecessary_operation.rs:56:5
| |
LL | Tuple(get_number()); LL | Tuple(get_number());
| ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `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` = note: `-D clippy::unnecessary-operation` implied by `-D warnings`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:52:5 --> $DIR/unnecessary_operation.rs:57:5
| |
LL | Struct { field: get_number() }; LL | Struct { field: get_number() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:53:5 --> $DIR/unnecessary_operation.rs:58:5
| |
LL | Struct { ..get_struct() }; LL | Struct { ..get_struct() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:54:5 --> $DIR/unnecessary_operation.rs:59:5
| |
LL | Enum::Tuple(get_number()); LL | Enum::Tuple(get_number());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:55:5 --> $DIR/unnecessary_operation.rs:60:5
| |
LL | Enum::Struct { field: get_number() }; LL | Enum::Struct { field: get_number() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:56:5 --> $DIR/unnecessary_operation.rs:61:5
| |
LL | 5 + get_number(); LL | 5 + get_number();
| ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:57:5 --> $DIR/unnecessary_operation.rs:62:5
| |
LL | *&get_number(); LL | *&get_number();
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:58:5 --> $DIR/unnecessary_operation.rs:63:5
| |
LL | &get_number(); LL | &get_number();
| ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:59:5 --> $DIR/unnecessary_operation.rs:64:5
| |
LL | (5, 6, get_number()); LL | (5, 6, get_number());
| ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:60:5 --> $DIR/unnecessary_operation.rs:65:5
|
LL | box get_number();
| ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
--> $DIR/unnecessary_operation.rs:61:5
| |
LL | get_number()..; LL | get_number()..;
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:62:5 --> $DIR/unnecessary_operation.rs:66:5
| |
LL | ..get_number(); LL | ..get_number();
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:63:5 --> $DIR/unnecessary_operation.rs:67:5
| |
LL | 5..get_number(); LL | 5..get_number();
| ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:64:5 --> $DIR/unnecessary_operation.rs:68:5
| |
LL | [42, get_number()]; LL | [42, get_number()];
| ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:65:5 --> $DIR/unnecessary_operation.rs:69:5
| |
LL | [42, 55][get_usize()]; LL | [42, 55][get_usize()];
| ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:66:5 --> $DIR/unnecessary_operation.rs:70:5
| |
LL | (42, get_number()).1; LL | (42, get_number()).1;
| ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:67:5 --> $DIR/unnecessary_operation.rs:71:5
| |
LL | [get_number(); 55]; LL | [get_number(); 55];
| ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:68:5 --> $DIR/unnecessary_operation.rs:72:5
| |
LL | [42; 55][get_usize()]; LL | [42; 55][get_usize()];
| ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:69:5 --> $DIR/unnecessary_operation.rs:73:5
| |
LL | / { LL | / {
LL | | get_number() LL | | get_number()
@ -117,12 +111,12 @@ LL | | };
| |______^ help: statement can be reduced to: `get_number();` | |______^ help: statement can be reduced to: `get_number();`
error: unnecessary operation error: unnecessary operation
--> $DIR/unnecessary_operation.rs:72:5 --> $DIR/unnecessary_operation.rs:76:5
| |
LL | / FooString { LL | / FooString {
LL | | s: String::from("blah"), LL | | s: String::from("blah"),
LL | | }; LL | | };
| |______^ help: statement can be reduced to: `String::from("blah");` | |______^ help: statement can be reduced to: `String::from("blah");`
error: aborting due to 20 previous errors error: aborting due to 19 previous errors

View file

@ -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 });
}

View file

@ -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 })
};
}

View file

@ -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