From: flip1995 Date: Thu, 8 Apr 2021 15:18:19 +0000 (+0200) Subject: Merge remote-tracking branch 'upstream/master' into rustup X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=ffa2b7da2942a4dd27375a339582d78b7bb154e7;p=rust.git Merge remote-tracking branch 'upstream/master' into rustup --- ffa2b7da2942a4dd27375a339582d78b7bb154e7 diff --cc clippy_lints/src/functions/must_use.rs index 00000000000,9ea8e2eaa2a..20288427b4a mode 000000,100644..100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@@ -1,0 -1,272 +1,272 @@@ + use rustc_ast::ast::Attribute; + use rustc_errors::Applicability; + use rustc_hir::def_id::DefIdSet; + use rustc_hir::{self as hir, def::Res, intravisit, QPath}; + use rustc_lint::{LateContext, LintContext}; + use rustc_middle::{ + hir::map::Map, + lint::in_external_macro, + ty::{self, Ty}, + }; + use rustc_span::{sym, Span}; + + use clippy_utils::attrs::is_proc_macro; + use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; + use clippy_utils::source::snippet_opt; + use clippy_utils::ty::is_must_use_ty; + use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method}; + + use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; + + pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { + let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attr = must_use_attr(attrs); + if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind { + let is_public = cx.access_levels.is_exported(item.hir_id()); + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + if let Some(attr) = attr { + check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); + return; + } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { + check_must_use_candidate( + cx, + sig.decl, + cx.tcx.hir().body(*body_id), + item.span, + item.hir_id(), + item.span.with_hi(sig.decl.output.span().hi()), + "this function could have a `#[must_use]` attribute", + ); + } + } + } + + pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { + if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind { + let is_public = cx.access_levels.is_exported(item.hir_id()); + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attr = must_use_attr(attrs); + if let Some(attr) = attr { + check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); + } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.hir_id()).is_none() { + check_must_use_candidate( + cx, + sig.decl, + cx.tcx.hir().body(*body_id), + item.span, + item.hir_id(), + item.span.with_hi(sig.decl.output.span().hi()), + "this method could have a `#[must_use]` attribute", + ); + } + } + } + + pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { + if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind { + let is_public = cx.access_levels.is_exported(item.hir_id()); + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + + let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attr = must_use_attr(attrs); + if let Some(attr) = attr { + check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); + } else if let hir::TraitFn::Provided(eid) = *eid { + let body = cx.tcx.hir().body(eid); + if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) { + check_must_use_candidate( + cx, + sig.decl, + body, + item.span, + item.hir_id(), + item.span.with_hi(sig.decl.output.span().hi()), + "this method could have a `#[must_use]` attribute", + ); + } + } + } + } + + fn check_needless_must_use( + cx: &LateContext<'_>, + decl: &hir::FnDecl<'_>, + item_id: hir::HirId, + item_span: Span, + fn_header_span: Span, + attr: &Attribute, + ) { + if in_external_macro(cx.sess(), item_span) { + return; + } + if returns_unit(decl) { + span_lint_and_then( + cx, + MUST_USE_UNIT, + fn_header_span, + "this unit-returning function has a `#[must_use]` attribute", + |diag| { + diag.span_suggestion( + attr.span, + "remove the attribute", + "".into(), + Applicability::MachineApplicable, + ); + }, + ); - } else if !attr.is_value_str() && is_must_use_ty(cx, return_ty(cx, item_id)) { ++ } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { + span_lint_and_help( + cx, + DOUBLE_MUST_USE, + fn_header_span, + "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`", + None, + "either add some descriptive text or remove the attribute", + ); + } + } + + fn check_must_use_candidate<'tcx>( + cx: &LateContext<'tcx>, + decl: &'tcx hir::FnDecl<'_>, + body: &'tcx hir::Body<'_>, + item_span: Span, + item_id: hir::HirId, + fn_span: Span, + msg: &str, + ) { + if has_mutable_arg(cx, body) + || mutates_static(cx, body) + || in_external_macro(cx.sess(), item_span) + || returns_unit(decl) + || !cx.access_levels.is_exported(item_id) + || is_must_use_ty(cx, return_ty(cx, item_id)) + { + return; + } + span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| { + if let Some(snippet) = snippet_opt(cx, fn_span) { + diag.span_suggestion( + fn_span, + "add the attribute", + format!("#[must_use] {}", snippet), + Applicability::MachineApplicable, + ); + } + }); + } + + fn returns_unit(decl: &hir::FnDecl<'_>) -> bool { + match decl.output { + hir::FnRetTy::DefaultReturn(_) => true, + hir::FnRetTy::Return(ty) => match ty.kind { + hir::TyKind::Tup(tys) => tys.is_empty(), + hir::TyKind::Never => true, + _ => false, + }, + } + } + + fn has_mutable_arg(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { + let mut tys = DefIdSet::default(); + body.params.iter().any(|param| is_mutable_pat(cx, param.pat, &mut tys)) + } + + fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) -> bool { + if let hir::PatKind::Wild = pat.kind { + return false; // ignore `_` patterns + } + if cx.tcx.has_typeck_results(pat.hir_id.owner.to_def_id()) { + is_mutable_ty(cx, cx.tcx.typeck(pat.hir_id.owner).pat_ty(pat), pat.span, tys) + } else { + false + } + } + + static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]]; + + fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool { + match *ty.kind() { + // primitive types are never mutable + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, + ty::Adt(adt, substs) => { + tys.insert(adt.did) && !ty.is_freeze(cx.tcx.at(span), cx.param_env) + || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did, path)) + && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)) + }, + ty::Tuple(substs) => substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys)), + ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, span, tys), + ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => { + mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, span, tys) + }, + // calling something constitutes a side effect, so return true on all callables + // also never calls need not be used, so return true for them, too + _ => true, + } + } + + struct StaticMutVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + mutates_static: bool, + } + + impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall}; + + if self.mutates_static { + return; + } + match expr.kind { + Call(_, args) | MethodCall(_, _, args, _) => { + let mut tys = DefIdSet::default(); + for arg in args { + if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + && is_mutable_ty( + self.cx, + self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg), + arg.span, + &mut tys, + ) + && is_mutated_static(arg) + { + self.mutates_static = true; + return; + } + tys.clear(); + } + }, + Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { + self.mutates_static |= is_mutated_static(target) + }, + _ => {}, + } + } + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + } + + fn is_mutated_static(e: &hir::Expr<'_>) -> bool { + use hir::ExprKind::{Field, Index, Path}; + + match e.kind { + Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), + Path(_) => true, + Field(inner, _) | Index(inner, _) => is_mutated_static(inner), + _ => false, + } + } + + fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { + let mut v = StaticMutVisitor { + cx, + mutates_static: false, + }; + intravisit::walk_expr(&mut v, &body.value); + v.mutates_static + } diff --cc clippy_lints/src/lib.rs index a99ed7656bf,cd92b551abd..7abd02c53f1 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@@ -4,9 -4,7 +4,8 @@@ #![feature(box_syntax)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(iter_zip)] #![feature(once_cell)] - #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] #![feature(control_flow_enum)] diff --cc clippy_lints/src/matches.rs index 2f2dc4cfc6b,a892e24482b..c8ee0abd3df --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@@ -1669,7 -1670,7 +1671,7 @@@ wher values.sort(); - for (a, b) in iter::zip(&values, &values[1..]) { - for (a, b) in values.iter().zip(values.iter().skip(1)) { ++ for (a, b) in iter::zip(&values, values.iter().skip(1)) { match (a, b) { (&Kind::Start(_, ra), &Kind::End(_, rb)) => { if ra.node != rb.node { diff --cc clippy_lints/src/missing_doc.rs index 21b4983a1af,d731a9fe223..dfab3e8a931 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@@ -93,9 -93,9 +93,9 @@@ impl MissingDoc return; } -- let has_doc = attrs -- .iter() - .any(|a| a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())); - .any(|a| a.is_doc_comment() || a.doc_str().is_some() || a.is_value_str() || Self::has_include(a.meta())); ++ let has_doc = attrs.iter().any(|a| { ++ a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta()) ++ }); if !has_doc { span_lint( cx, diff --cc clippy_lints/src/pattern_type_mismatch.rs index c0c2ab67e38,8c198cecd6a..9bab783998a --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@@ -135,8 -134,8 +135,8 @@@ impl<'tcx> LateLintPass<'tcx> for Patte hir_id: HirId, ) { if let Some(fn_sig) = cx.typeck_results().liberated_fn_sigs().get(hir_id) { - for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) { + for (param, ty) in iter::zip(body.params, fn_sig.inputs()) { - apply_lint(cx, ¶m.pat, ty, DerefPossible::Impossible); + apply_lint(cx, param.pat, ty, DerefPossible::Impossible); } } } diff --cc clippy_lints/src/unnecessary_sort_by.rs index 6becff9662a,03711eb5b65..347d858b640 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@@ -80,10 -79,10 +80,9 @@@ fn mirrored_exprs mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) }, // Two arrays with mirrored contents - (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => left_exprs - .iter() - .zip(right_exprs.iter()) - .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => { - iter::zip(*left_exprs, *right_exprs) - .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) - } ++ iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) ++ }, // The two exprs are function calls. // Check to see that the function itself and its arguments are mirrored (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { @@@ -99,14 -100,16 +98,13 @@@ ExprKind::MethodCall(right_segment, _, right_args, _), ) => { left_segment.ident == right_segment.ident - && left_args - .iter() - .zip(right_args.iter()) + && iter::zip(*left_args, *right_args) .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) - } + }, // Two tuples with mirrored contents - (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => left_exprs - .iter() - .zip(right_exprs.iter()) - .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { - iter::zip(*left_exprs, *right_exprs) - .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) - } ++ iter::zip(*left_exprs, *right_exprs).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) ++ }, // Two binary ops, which are the same operation and which have mirrored arguments (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { left_op.node == right_op.node @@@ -143,8 -146,10 +141,7 @@@ }, )), ) => { - (iter::zip(*left_segments, *right_segments) - (left_segments - .iter() - .zip(right_segments.iter()) -- .all(|(left, right)| left.ident == right.ident) ++ (iter::zip(*left_segments, *right_segments).all(|(left, right)| left.ident == right.ident) && left_segments .iter() .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) diff --cc clippy_lints/src/utils/inspector.rs index b3fe66ed428,32d34e8d31e..4665eeeff7b --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@@ -318,10 -319,6 +318,10 @@@ fn print_expr(cx: &LateContext<'_>, exp print_expr(cx, out_expr, indent + 1); } }, + hir::InlineAsmOperand::Const { anon_const } => { + println!("{}anon_const:", ind); + print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); - } ++ }, } } }, diff --cc clippy_utils/src/consts.rs index 8af10ebe777,ebe896b7ae8..2a305d8bcbe --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@@ -140,12 -139,12 +140,10 @@@ impl Constant (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r), (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r), (&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)), - (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => { - iter::zip(l, r) - .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri)) - .find(|r| r.map_or(true, |o| o != Ordering::Equal)) - .unwrap_or_else(|| Some(l.len().cmp(&r.len()))) - } - (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => l - .iter() - .zip(r.iter()) ++ (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => iter::zip(l, r) + .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri)) + .find(|r| r.map_or(true, |o| o != Ordering::Equal)) + .unwrap_or_else(|| Some(l.len().cmp(&r.len()))), (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => { match Self::partial_cmp(tcx, cmp_type, lv, rv) { Some(Equal) => Some(ls.cmp(rs)), diff --cc clippy_utils/src/lib.rs index 6b235875c20,6088cd323c4..185ef296f3f --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@@ -1,7 -1,5 +1,6 @@@ #![feature(box_patterns)] #![feature(in_band_lifetimes)] +#![feature(iter_zip)] - #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(rustc_private)] #![recursion_limit = "512"] #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)] diff --cc clippy_utils/src/qualify_min_const_fn.rs index dac4d93499d,1391f7505e2..b52cbf31e35 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@@ -210,21 -210,21 +210,19 @@@ fn check_statement(tcx: TyCtxt<'tcx>, b StatementKind::Assign(box (place, rval)) => { check_place(tcx, *place, span, body)?; check_rvalue(tcx, body, def_id, rval, span) -- } ++ }, - StatementKind::FakeRead(_, place) | + StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), // just an assignment StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body), StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), -- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping{ -- dst, src, count, -- }) => { -- check_operand(tcx, dst, span, body)?; -- check_operand(tcx, src, span, body)?; -- check_operand(tcx, count, span, body) -- } ++ StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => { ++ check_operand(tcx, dst, span, body)?; ++ check_operand(tcx, src, span, body)?; ++ check_operand(tcx, count, span, body) ++ }, // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_)