Change:
When using and together, the compiler complains that is an unused import even when a call to something like exists. Removing gets rid of the warning and the crate compiles. However, the crate will fail to link (for example with ) unless the is there. It seems like the warning is a bug unless the intent is to have also bring in foo itself. Here's a small crate that shows the example. This was originally found in rust-core-foundation.
Looking at the code, that's a genuinely unused import when not compiling with . I ran into this when removing unused imports in the compiler, and you can prefix the import with so that the import is only resolved when testing. Other options I've seen are to have a which is 'd off, or just put the in the function itself.
You're right. In this case I moved the inside the test function.

Discussion:
}; use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg}; use if_chain::if_chain; <del> use itertools::Itertools; </del> use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability;

fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId) -> bool { if_chain! { <del> if let ExprKind::Path(ref qpath) = expr.kind; if let QPath::Resolved(None, ref path) = *qpath; </del> <ins> if let ExprKind::Path(qpath) = &expr.kind; if let QPath::Resolved(None, path) = qpath; </ins> if path.segments.len() == 1; if let Res::Local(local_id) = qpath_res(cx, qpath, expr.hir_id); // our variable! if local_id == var; then { <del> return true; </del> <ins> true } else { false </ins> } } <ins> } </ins> <del> false </del> <ins> #[derive(Clone, Copy)] enum OffsetSign { Positive, Negative, </ins> } struct Offset { value: String, <del> negate: bool, </del> <ins> sign: OffsetSign, </ins> } impl Offset { <del> fn negative(s: String) -> Self { Self { value: s, negate: true } </del> <ins> fn negative(value: String) -> Self { Self { value, sign: OffsetSign::Negative, } </ins> } <del> fn positive(s: String) -> Self { </del> <ins> fn positive(value: String) -> Self { </ins> Self { <del> value: s, negate: false, </del> <ins> value, sign: OffsetSign::Positive, </ins> } } }

is_slice || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) } <del> fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId) -> Option<FixedOffsetVar> { </del> <ins> fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { if let ExprKind::MethodCall(method, _, args) = expr.kind; if method.ident.name == sym!(clone); if args.len() == 1; if let Some(arg) = args.get(0); then { arg } else { expr } } } fn get_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, idx: &Expr<'_>, var: HirId) -> Option<Offset> { </ins> fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr<'_>, var: HirId) -> Option<String> { <del> match e.kind { ExprKind::Lit(ref l) => match l.node { </del> <ins> match &e.kind { ExprKind::Lit(l) => match l.node { </ins> ast::LitKind::Int(x, _ty) => Some(x.to_string()), _ => None, },

} } <del> if let ExprKind::Index(ref seqexpr, ref idx) = expr.kind { let ty = cx.tables.expr_ty(seqexpr); if !is_slice_like(cx, ty) { return None; } let offset = match idx.kind { ExprKind::Binary(op, ref lhs, ref rhs) => match op.node { BinOpKind::Add => { let offset_opt = if same_var(cx, lhs, var) { extract_offset(cx, rhs, var) } else if same_var(cx, rhs, var) { extract_offset(cx, lhs, var) } else { None }; offset_opt.map(Offset::positive) }, BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative), _ => None, }, ExprKind::Path(..) => { if same_var(cx, idx, var) { Some(Offset::positive("0".into())) </del> <ins> match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { let offset_opt = if same_var(cx, lhs, var) { extract_offset(cx, rhs, var) } else if same_var(cx, rhs, var) { extract_offset(cx, lhs, var) </ins> } else { None <del> } </del> <ins> }; offset_opt.map(Offset::positive) </ins> }, <ins> BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative), </ins> _ => None, <del> }; offset.map(|o| FixedOffsetVar { var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()), offset: o, }) } else { None } } fn fetch_cloned_fixed_offset_var<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId, ) -> Option<FixedOffsetVar> { if_chain! { if let ExprKind::MethodCall(ref method, _, ref args) = expr.kind; if method.ident.name == sym!(clone); if args.len() == 1; if let Some(arg) = args.get(0); then { return get_fixed_offset_var(cx, arg, var); } </del> <ins> }, ExprKind::Path(..) if same_var(cx, idx, var) => Some(Offset::positive("0".into())), _ => None, </ins> } <del> get_fixed_offset_var(cx, expr, var) </del> } <del> fn get_indexed_assignments<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, body: &Expr<'_>, var: HirId, ) -> Vec<(FixedOffsetVar, FixedOffsetVar)> { fn get_assignment<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, e: &Expr<'_>, var: HirId, ) -> Option<(FixedOffsetVar, FixedOffsetVar)> { if let ExprKind::Assign(ref lhs, ref rhs, _) = e.kind { match ( get_fixed_offset_var(cx, lhs, var), fetch_cloned_fixed_offset_var(cx, rhs, var), ) { (Some(offset_left), Some(offset_right)) => { // Source and destination must be different if offset_left.var_name == offset_right.var_name { None } else { Some((offset_left, offset_right)) } }, _ => None, } </del> <ins> fn get_assignments<'a, 'tcx>( body: &'tcx Expr<'tcx>, ) -> impl Iterator<Item = Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>> { fn get_assignment<'a, 'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { if let ExprKind::Assign(lhs, rhs, _) = e.kind { Some((lhs, rhs)) </ins> } else { None } } <del> if let ExprKind::Block(ref b, _) = body.kind { let Block { ref stmts, ref expr, .. } = **b; </del> <ins> // This is one of few ways to return different iterators // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434 let mut iter_a = None; let mut iter_b = None; if let ExprKind::Block(b, _) = body.kind { let Block { stmts, expr, .. } = *b; </ins> <del> stmts </del> <ins> iter_a = stmts </ins> .iter() <del> .map(|stmt| match stmt.kind { </del> <ins> .filter_map(|stmt| match stmt.kind { </ins> StmtKind::Local(..) | StmtKind::Item(..) => None, <del> StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => Some(get_assignment(cx, e, var)), </del> <ins> StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e), </ins> }) <del> .chain(expr.as_ref().into_iter().map(|e| Some(get_assignment(cx, &*e, var)))) .filter_map(|op| op) .collect::<Option<Vec<_>>>() .unwrap_or_default() </del> <ins> .chain(expr.into_iter()) .map(get_assignment) .into() </ins> } else { <del> get_assignment(cx, body, var).into_iter().collect() </del> <ins> iter_b = Some(get_assignment(body)) </ins> } <ins> iter_a.into_iter().flatten().chain(iter_b.into_iter()) </ins> } /// Checks for for loops that sequentially copy items from one slice-like

) { if let Some(higher::Range { start: Some(start), <del> ref end, </del> <ins> end: Some(end), </ins> limits, }) = higher::range(cx, arg) { // the var must be a single name if let PatKind::Binding(_, canonical_id, _, _) = pat.kind { <del> let print_sum = |arg1: &Offset, arg2: &Offset| -> String { match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) { ("0", _, "0", _) => "".into(), ("0", _, x, false) | (x, false, "0", false) => x.into(), ("0", _, x, true) | (x, false, "0", true) => format!("-{}", x), (x, false, y, false) => format!("({} + {})", x, y), (x, false, y, true) => { </del> <ins> fn print_sum(arg1: &str, arg2: &Offset) -> String { match (arg1, &arg2.value[..], arg2.sign) { ("0", "0", _) => "0".into(), ("0", x, OffsetSign::Positive) | (x, "0", _) => x.into(), ("0", x, OffsetSign::Negative) => format!("-{}", x), (x, y, OffsetSign::Positive) => format!("({} + {})", x, y), (x, y, OffsetSign::Negative) => { </ins> if x == y { "0".into() } else { format!("({} - {})", x, y) } }, <del> (x, true, y, false) => { if x == y { "0".into() } else { format!("({} - {})", y, x) } }, (x, true, y, true) => format!("-({} + {})", x, y), </del> } <del> }; </del> <ins> } </ins> <del> let print_limit = |end: &Option<&Expr<'_>>, offset: Offset, var_name: &str| { if let Some(end) = *end { if_chain! { if let ExprKind::MethodCall(ref method, _, ref len_args) = end.kind; if method.ident.name == sym!(len); if len_args.len() == 1; if let Some(arg) = len_args.get(0); if snippet(cx, arg.span, "??") == var_name; then { return if offset.negate { format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value) } else { String::new() }; } } </del> <ins> fn print_offset(start_str: &str, inline_offset: &Offset) -> String { let offset = print_sum(start_str, inline_offset); if offset.as_str() == "0" { "".into() } else { offset } } </ins> <del> let end_str = match limits { ast::RangeLimits::Closed => { let end = sugg::Sugg::hir(cx, end, "<count>"); format!("{}", end + sugg::ONE) }, ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")), }; </del> <ins> let print_limit = |end: &Expr<'_>, offset: Offset, var_name: &str| { if_chain! { if let ExprKind::MethodCall(method, _, len_args) = end.kind; if method.ident.name == sym!(len); if len_args.len() == 1; if let Some(arg) = len_args.get(0); if snippet(cx, arg.span, "??") == var_name; then { match offset.sign { OffsetSign::Negative => format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value), OffsetSign::Positive => "".into(), } } else { let end_str = match limits { ast::RangeLimits::Closed => { let end = sugg::Sugg::hir(cx, end, "<count>"); format!("{}", end + sugg::ONE) }, ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")), }; </ins> <del> print_sum(&Offset::positive(end_str), &offset) } else { "..".into() </del> <ins> print_sum(&end_str, &offset) } </ins> } }; // The only statements in the for loops can be indexed assignments from // indexed retrievals. <del> let manual_copies = get_indexed_assignments(cx, body, canonical_id); let big_sugg = manual_copies .into_iter() .map(|(dst_var, src_var)| { let start_str = Offset::positive(snippet(cx, start.span, "").to_string()); let dst_offset = print_sum(&start_str, &dst_var.offset); let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name); let src_offset = print_sum(&start_str, &src_var.offset); let src_limit = print_limit(end, src_var.offset, &src_var.var_name); let dst = if dst_offset == "" && dst_limit == "" { dst_var.var_name } else { format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit) }; </del> <ins> let big_sugg = get_assignments(body) .map(|o| { o.and_then(|(lhs, rhs)| { let rhs = fetch_cloned_expr(rhs); if_chain! { if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind; if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind; if is_slice_like(cx, cx.tables.expr_ty(seqexpr_left)) && is_slice_like(cx, cx.tables.expr_ty(seqexpr_right)); if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id); if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id); let var_name_left = snippet_opt(cx, seqexpr_left.span).unwrap_or_else(|| "???".into()); let var_name_right = snippet_opt(cx, seqexpr_right.span).unwrap_or_else(|| "???".into()); // Source and destination must be different if var_name_left != var_name_right; then { Some((FixedOffsetVar { var_name: var_name_left, offset: offset_left }, FixedOffsetVar { var_name: var_name_right, offset: offset_right })) } else { None } } }) }) .map(|o| { o.map(|(dst_var, src_var)| { let start_str = snippet(cx, start.span, "").to_string(); let dst_offset = print_offset(&start_str, &dst_var.offset); let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name); let src_offset = print_offset(&start_str, &src_var.offset); let src_limit = print_limit(end, src_var.offset, &src_var.var_name); let dst = if dst_offset == "" && dst_limit == "" { dst_var.var_name } else { format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit) }; </ins> <del> format!( "{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name, src_offset, src_limit ) </del> <ins> format!( "{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name, src_offset, src_limit ) }) </ins> }) <del> .join("n    "); </del> <ins> .collect::<Option<Vec<_>>>() .filter(|v| !v.is_empty()) .map(|v| v.join("n    ")); </ins> <del> if !big_sugg.is_empty() { </del> <ins> if let Some(big_sugg) = big_sugg { </ins> span_lint_and_sugg( cx, MANUAL_MEMCPY,

for i in from..from + 3 { dst[i] = src[i - from]; } <ins> // `RangeTo` `for` loop - don't trigger lint for i in 0.. { dst[i] = src[i]; } </ins> } #[warn(clippy::needless_range_loop, clippy::manual_memcpy)]

--> $DIR/manual_memcpy.rs:94:14 | LL |     for i in from..from + src.len() { <del> |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[0..(from + src.len() - from)])` </del> <ins> |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[..(from + src.len() - from)])` </ins> error: it looks like you're manually copying between slices --> $DIR/manual_memcpy.rs:98:14 | LL |     for i in from..from + 3 { <del> |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[0..(from + 3 - from)])` </del> <ins> |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[..(from + 3 - from)])` </ins> error: it looks like you're manually copying between slices <del> --> $DIR/manual_memcpy.rs:105:14 </del> <ins> --> $DIR/manual_memcpy.rs:110:14 </ins> | LL |     for i in 0..src.len() { |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`