diff options
42 files changed, 321 insertions, 569 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 405e9035c4c..a0a63620c08 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -13,7 +13,7 @@ use rustc_session::parse::feature_err; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP}; +use rustc_span::DUMMY_SP; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] { @@ -1308,16 +1308,13 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into: /// ```rust /// { - /// let result = match ::std::iter::IntoIterator::into_iter(<head>) { + /// let result = match IntoIterator::into_iter(<head>) { /// mut iter => { /// [opt_ident]: loop { - /// let mut __next; - /// match ::std::iter::Iterator::next(&mut iter) { - /// ::std::option::Option::Some(val) => __next = val, - /// ::std::option::Option::None => break + /// match Iterator::next(&mut iter) { + /// None => break, + /// Some(<pat>) => <body>, /// }; - /// let <pat> = __next; - /// StmtKind::Expr(<body>); /// } /// } /// }; @@ -1332,133 +1329,75 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Block, opt_label: Option<Label>, ) -> hir::Expr<'hir> { - // expand <head> let head = self.lower_expr_mut(head); - let desugared_span = - self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None); - let e_span = self.lower_span(e.span); - - let iter = Ident::with_dummy_span(sym::iter); - - let next_ident = Ident::with_dummy_span(sym::__next); - let (next_pat, next_pat_hid) = self.pat_ident_binding_mode( - desugared_span, - next_ident, - hir::BindingAnnotation::Mutable, - ); - - // `::std::option::Option::Some(val) => __next = val` - let pat_arm = { - let val_ident = Ident::with_dummy_span(sym::val); - let pat_span = self.lower_span(pat.span); - let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident); - let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid); - let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid); - let assign = self.arena.alloc(self.expr( - pat_span, - hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)), - ThinVec::new(), - )); - let some_pat = self.pat_some(pat_span, val_pat); - self.arm(some_pat, assign) - }; + let pat = self.lower_pat(pat); + let for_span = + self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None); + let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None); + let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None); - // `::std::option::Option::None => break` - let break_arm = { + // `None => break` + let none_arm = { let break_expr = - self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new())); - let pat = self.pat_none(e_span); + self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new())); + let pat = self.pat_none(for_span); self.arm(pat, break_expr) }; + // Some(<pat>) => <body>, + let some_arm = { + let some_pat = self.pat_some(pat_span, pat); + let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); + let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new())); + self.arm(some_pat, body_expr) + }; + // `mut iter` + let iter = Ident::with_dummy_span(sym::iter); let (iter_pat, iter_pat_nid) = - self.pat_ident_binding_mode(desugared_span, iter, hir::BindingAnnotation::Mutable); + self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable); - // `match ::std::iter::Iterator::next(&mut iter) { ... }` + // `match Iterator::next(&mut iter) { ... }` let match_expr = { - let iter = self.expr_ident(desugared_span, iter, iter_pat_nid); - let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter); + let iter = self.expr_ident(head_span, iter, iter_pat_nid); + let ref_mut_iter = self.expr_mut_addr_of(head_span, iter); let next_expr = self.expr_call_lang_item_fn( - desugared_span, + head_span, hir::LangItem::IteratorNext, arena_vec![self; ref_mut_iter], ); - let arms = arena_vec![self; pat_arm, break_arm]; + let arms = arena_vec![self; none_arm, some_arm]; - self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar) + self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar) }; - let match_stmt = self.stmt_expr(desugared_span, match_expr); - - let next_expr = self.expr_ident(desugared_span, next_ident, next_pat_hid); - - // `let mut __next` - let next_let = self.stmt_let_pat( - None, - desugared_span, - None, - next_pat, - hir::LocalSource::ForLoopDesugar, - ); + let match_stmt = self.stmt_expr(for_span, match_expr); - // `let <pat> = __next` - let pat = self.lower_pat(pat); - let pat_let = self.stmt_let_pat( - None, - desugared_span, - Some(next_expr), - pat, - hir::LocalSource::ForLoopDesugar, - ); - - let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); - let body_expr = self.expr_block(body_block, ThinVec::new()); - let body_stmt = self.stmt_expr(body_block.span, body_expr); - - let loop_block = self.block_all( - e_span, - arena_vec![self; next_let, match_stmt, pat_let, body_stmt], - None, - ); + let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None); // `[opt_ident]: loop { ... }` let kind = hir::ExprKind::Loop( loop_block, self.lower_label(opt_label), hir::LoopSource::ForLoop, - self.lower_span(e_span.with_hi(head.span.hi())), + self.lower_span(for_span.with_hi(head.span.hi())), ); - let loop_expr = self.arena.alloc(hir::Expr { - hir_id: self.lower_node_id(e.id), - kind, - span: self.lower_span(e.span), - }); + let loop_expr = + self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span }); // `mut iter => { ... }` let iter_arm = self.arm(iter_pat, loop_expr); - let into_iter_span = self.mark_span_with_reason( - DesugaringKind::ForLoop(ForLoopLoc::IntoIter), - head.span, - None, - ); - // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` let into_iter_expr = { self.expr_call_lang_item_fn( - into_iter_span, + head_span, hir::LangItem::IntoIterIntoIter, arena_vec![self; head], ) }; - // #82462: to correctly diagnose borrow errors, the block that contains - // the iter expr needs to have a span that covers the loop body. - let desugared_full_span = - self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None); - let match_expr = self.arena.alloc(self.expr_match( - desugared_full_span, + for_span, into_iter_expr, arena_vec![self; iter_arm], hir::MatchSource::ForLoopDesugar, @@ -1472,7 +1411,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // surrounding scope of the `match` since the `match` is not a terminating scope. // // Also, add the attributes to the outer returned expr node. - self.expr_drop_temps_mut(desugared_full_span, match_expr, attrs.into()) + self.expr_drop_temps_mut(for_span, match_expr, attrs.into()) } /// Desugar `ExprKind::Try` from: `<expr>?` into: diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 79973ab170c..db8268c8e2e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -13,7 +13,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{sym, DesugaringKind, Span}; use crate::region_infer::BlameConstraint; use crate::{ @@ -135,7 +135,16 @@ impl BorrowExplanation { should_note_order, } => { let local_decl = &body.local_decls[dropped_local]; - let (dtor_desc, type_desc) = match local_decl.ty.kind() { + let mut ty = local_decl.ty; + if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) { + if let ty::Adt(adt, substs) = local_decl.ty.kind() { + if tcx.is_diagnostic_item(sym::Option, adt.did) { + // in for loop desugaring, only look at the `Some(..)` inner type + ty = substs.type_at(0); + } + } + } + let (dtor_desc, type_desc) = match ty.kind() { // If type is an ADT that implements Drop, then // simplify output by reporting just the ADT name. ty::Adt(adt, _substs) if adt.has_dtor(tcx) && !adt.is_box() => { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index a4df277a7b0..79623e26eb7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,11 +13,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; -use rustc_span::{ - hygiene::{DesugaringKind, ForLoopLoc}, - symbol::sym, - Span, -}; +use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span}; use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; @@ -955,10 +951,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let kind = kind.unwrap_or_else(|| { // This isn't a 'special' use of `self` debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); - let implicit_into_iter = matches!( - fn_call_span.desugaring_kind(), - Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) - ); + let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn() + && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop); let parent_self_ty = parent .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl) .and_then(|did| match tcx.type_of(did).kind() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index d5ff4c6766f..46e2a99a0d0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -445,15 +445,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }, ))) => { // check if the RHS is from desugaring - let locations = self.body.find_assignments(local); - let opt_assignment_rhs_span = locations - .first() - .map(|&location| self.body.source_info(location).span); - let opt_desugaring_kind = - opt_assignment_rhs_span.and_then(|span| span.desugaring_kind()); - match opt_desugaring_kind { + let opt_assignment_rhs_span = + self.body.find_assignments(local).first().map(|&location| { + let stmt = &self.body[location.block].statements + [location.statement_index]; + match stmt.kind { + mir::StatementKind::Assign(box ( + _, + mir::Rvalue::Use(mir::Operand::Copy(place)), + )) => { + self.body.local_decls[place.local].source_info.span + } + _ => self.body.source_info(location).span, + } + }); + match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) { // on for loops, RHS points to the iterator part - Some(DesugaringKind::ForLoop(_)) => { + Some(DesugaringKind::ForLoop) => { self.suggest_similar_mut_method_for_for_loop(&mut err); Some(( false, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a4db57bfc11..c67d3df3ded 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1821,8 +1821,6 @@ impl<'hir> QPath<'hir> { pub enum LocalSource { /// A `match _ { .. }`. Normal, - /// A desugared `for _ in _ { .. }` loop. - ForLoopDesugar, /// When lowering async functions, we create locals within the `async move` so that /// all parameters are dropped after the future is polled. /// diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index b1f78a83e74..b30076100bb 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -2,6 +2,7 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; use crate::hir::{self, HirId, PatKind}; use rustc_data_structures::stable_set::FxHashSet; +use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -143,4 +144,14 @@ impl hir::Pat<'_> { }); result } + + /// If the pattern is `Some(<pat>)` from a desugared for loop, returns the inner pattern + pub fn for_loop_some(&self) -> Option<&Self> { + if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) { + if let hir::PatKind::Struct(_, [pat_field], _) = self.kind { + return Some(pat_field.pat); + } + } + None + } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index e00003face9..a7e019a53ee 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -5,13 +5,12 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; +use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat}; use rustc_middle::hir::map::Map; use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt}; -use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; use std::borrow::Cow; @@ -26,6 +25,7 @@ struct FindHirNodeVisitor<'a, 'tcx> { found_closure: Option<&'tcx Expr<'tcx>>, found_method_call: Option<&'tcx Expr<'tcx>>, found_exact_method_call: Option<&'tcx Expr<'tcx>>, + found_for_loop_iter: Option<&'tcx Expr<'tcx>>, found_use_diagnostic: Option<UseDiagnostic<'tcx>>, } @@ -41,6 +41,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { found_closure: None, found_method_call: None, found_exact_method_call: None, + found_for_loop_iter: None, found_use_diagnostic: None, } } @@ -111,6 +112,15 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind { + if let Some(pat) = arm.pat.for_loop_some() { + if let Some(ty) = self.node_ty_contains_target(pat.hir_id) { + self.found_for_loop_iter = Some(scrutinee); + self.found_node_ty = Some(ty); + return; + } + } + } if let ExprKind::MethodCall(_, call_span, exprs, _) = expr.kind { if call_span == self.target_span && Some(self.target) @@ -643,10 +653,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let msg = if let Some(simple_ident) = pattern.simple_ident() { match pattern.span.desugaring_kind() { None => format!("consider giving `{}` {}", simple_ident, suffix), - Some(DesugaringKind::ForLoop(_)) => { - "the element type for this iterator is not specified".to_string() - } - _ => format!("this needs {}", suffix), + Some(_) => format!("this needs {}", suffix), } } else { format!("consider giving this pattern {}", suffix) @@ -719,6 +726,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // = note: type must be known at this point self.annotate_method_call(segment, e, &mut err); } + } else if let Some(scrutinee) = local_visitor.found_for_loop_iter { + err.span_label( + scrutinee.span, + "the element type for this iterator is not specified".to_string(), + ); } // Instead of the following: // error[E0282]: type annotations needed diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 0e70d49ef49..881b14278e9 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -395,7 +395,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { match expn_data.kind { ExpnKind::Inlined | ExpnKind::Root - | ExpnKind::Desugaring(DesugaringKind::ForLoop(_) | DesugaringKind::WhileLoop) => false, + | ExpnKind::Desugaring(DesugaringKind::ForLoop | DesugaringKind::WhileLoop) => false, ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { // Dummy span for the `def_site` means it's an external macro. diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e28fd2c5081..d74c53fae53 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -74,19 +74,16 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { let (msg, sp) = match loc.source { hir::LocalSource::Normal => ("local binding", Some(loc.span)), - hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None), hir::LocalSource::AsyncFn => ("async fn binding", None), hir::LocalSource::AwaitDesugar => ("`await` future binding", None), hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), }; self.check_irrefutable(&loc.pat, msg, sp); - self.check_patterns(&loc.pat, Irrefutable); } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { intravisit::walk_param(self, param); self.check_irrefutable(¶m.pat, "function argument", None); - self.check_patterns(¶m.pat, Irrefutable); } } @@ -161,12 +158,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { fn check_match( &mut self, scrut: &hir::Expr<'_>, - arms: &'tcx [hir::Arm<'tcx>], + hir_arms: &'tcx [hir::Arm<'tcx>], source: hir::MatchSource, ) { let mut cx = self.new_cx(scrut.hir_id); - for arm in arms { + for arm in hir_arms { // Check the arm for some things unrelated to exhaustiveness. self.check_patterns(&arm.pat, Refutable); if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { @@ -178,7 +175,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let mut have_errors = false; - let arms: Vec<_> = arms + let arms: Vec<_> = hir_arms .iter() .map(|hir::Arm { pat, guard, .. }| MatchArm { pat: self.lower_pattern(&mut cx, pat, &mut have_errors), @@ -196,6 +193,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); match source { + // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` + // when the iterator is an uninhabited type. unreachable_code will trigger instead. + hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {} hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { report_arm_reachability(&cx, &report) } @@ -208,7 +208,13 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let is_empty_match = arms.is_empty(); let witnesses = report.non_exhaustiveness_witnesses; if !witnesses.is_empty() { - non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match); + if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 { + // the for loop pattern is not irrefutable + let pat = hir_arms[1].pat.for_loop_some().unwrap(); + self.check_irrefutable(pat, "`for` loop binding", None); + } else { + non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match); + } } } @@ -225,6 +231,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let witnesses = report.non_exhaustiveness_witnesses; if witnesses.is_empty() { // The pattern is irrefutable. + self.check_patterns(pat, Irrefutable); return; } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 724d1904dc3..d590776676b 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1099,18 +1099,11 @@ pub enum DesugaringKind { OpaqueTy, Async, Await, - ForLoop(ForLoopLoc), + ForLoop, LetElse, WhileLoop, } -/// A location in the desugaring of a `for` loop -#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] -pub enum ForLoopLoc { - Head, - IntoIter, -} - impl DesugaringKind { /// The description wording should combine well with "desugaring of {}". pub fn descr(self) -> &'static str { @@ -1121,7 +1114,7 @@ impl DesugaringKind { DesugaringKind::QuestionMark => "operator `?`", DesugaringKind::TryBlock => "`try` block", DesugaringKind::OpaqueTy => "`impl Trait`", - DesugaringKind::ForLoop(_) => "`for` loop", + DesugaringKind::ForLoop => "`for` loop", DesugaringKind::LetElse => "`let...else`", DesugaringKind::WhileLoop => "`while` loop", } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 1445c59710c..66c01140abc 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -41,7 +41,7 @@ pub mod edition; use edition::Edition; pub mod hygiene; use hygiene::Transparency; -pub use hygiene::{DesugaringKind, ExpnKind, ForLoopLoc, MacroKind}; +pub use hygiene::{DesugaringKind, ExpnKind, MacroKind}; pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext}; pub mod def_id; use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE}; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9992b1f31fe..0d556b5eda6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -269,7 +269,6 @@ symbols! { __D, __H, __S, - __next, __try_var, _args, _d, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index d5c7cf71116..a90140a9b50 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP}; +use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::fmt; @@ -685,7 +685,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &obligation.cause.code { parent_code.clone() - } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) = + } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = span.ctxt().outer_expn_data().kind { Lrc::new(obligation.cause.code.clone()) @@ -765,8 +765,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // This if is to prevent a special edge-case if matches!( span.ctxt().outer_expn_data().kind, - ExpnKind::Root - | ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter)) + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) ) { // We don't want a borrowing suggestion on the fields in structs, // ``` diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index a8365071d61..a370485102e 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -549,13 +549,10 @@ mod fn_keyword {} /// { /// let result = match IntoIterator::into_iter(iterator) { /// mut iter => loop { -/// let next; /// match iter.next() { -/// Some(val) => next = val, /// None => break, +/// Some(loop_variable) => { code(); }, /// }; -/// let loop_variable = next; -/// let () = { code(); }; /// }, /// }; /// result diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index 1b96cd54c3e..d3687d5b908 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -183,7 +183,7 @@ pub fn add_loop_label_to_break() { #[cfg(not(any(cfail1,cfail4)))] #[rustc_clean(cfg="cfail2", except="hir_owner_nodes")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_loop_label_to_break() { let mut _x = 0; diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff index 02f6e55a9a8..2dfc94f2186 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -7,39 +7,29 @@ let mut _2: std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 let mut _3: std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 let mut _5: (); // in scope 0 at $DIR/remove_storage_markers.rs:6:1: 11:2 - let _7: (); // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let mut _8: std::option::Option<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let _6: (); // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _7: std::option::Option<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _8: &mut std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 let mut _9: &mut std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let mut _10: &mut std::ops::Range<i32>; // in scope 0 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let mut _11: isize; // in scope 0 at $DIR/remove_storage_markers.rs:8:9: 8:10 - let mut _13: i32; // in scope 0 at $DIR/remove_storage_markers.rs:8:9: 8:10 - let mut _14: !; // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6 - let _16: (); // in scope 0 at $DIR/remove_storage_markers.rs:8:20: 10:6 - let mut _17: i32; // in scope 0 at $DIR/remove_storage_markers.rs:9:16: 9:17 + let mut _10: isize; // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6 + let mut _11: !; // in scope 0 at $DIR/remove_storage_markers.rs:8:5: 10:6 + let mut _13: i32; // in scope 0 at $DIR/remove_storage_markers.rs:9:16: 9:17 scope 1 { debug sum => _1; // in scope 1 at $DIR/remove_storage_markers.rs:7:9: 7:16 let mut _4: std::ops::Range<i32>; // in scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 scope 2 { debug iter => _4; // in scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let mut _6: i32; // in scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let _12: i32; // in scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10 scope 3 { - debug __next => _6; // in scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let _12: i32; // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 - let _15: i32; // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 - scope 4 { - debug val => _12; // in scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10 - } - scope 5 { - debug i => _15; // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10 - } - scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 - debug self => _9; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 - let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 - } + debug i => _12; // in scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 + } + scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 + debug self => _8; // in scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _14: &mut std::ops::Range<i32>; // in scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19 } } - scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 - debug self => _3; // in scope 6 at $DIR/remove_storage_markers.rs:8:14: 8:19 + scope 4 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 + debug self => _3; // in scope 4 at $DIR/remove_storage_markers.rs:8:14: 8:19 } } @@ -50,7 +40,7 @@ - StorageLive(_3); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 (_3.0: i32) = const 0_i32; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 (_3.1: i32) = const 10_i32; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 - _2 = move _3; // scope 6 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _2 = move _3; // scope 4 at $DIR/remove_storage_markers.rs:8:14: 8:19 - StorageDead(_3); // scope 1 at $DIR/remove_storage_markers.rs:8:18: 8:19 - StorageLive(_4); // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 _4 = move _2; // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19 @@ -59,64 +49,51 @@ bb1: { - StorageLive(_6); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageLive(_7); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageLive(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageLive(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageLive(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 - _10 = &mut _4; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 - _9 = &mut (*_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageLive(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 - _18 = &mut (*_9); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 - _8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_7); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_8); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_9); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _9 = &mut _4; // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _8 = &mut (*_9); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_14); // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _14 = &mut (*_8); // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19 // mir::Constant // + span: $DIR/remove_storage_markers.rs:8:14: 8:19 // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) } } bb2: { - _0 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6 -- StorageDead(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 -- StorageDead(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 -- StorageDead(_7); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 +- StorageLive(_12); // scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10 + _12 = ((_7 as Some).0: i32); // scope 2 at $DIR/remove_storage_markers.rs:8:9: 8:10 +- StorageLive(_13); // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17 + _13 = _12; // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17 + _1 = Add(_1, move _13); // scope 3 at $DIR/remove_storage_markers.rs:9:9: 9:17 +- StorageDead(_13); // scope 3 at $DIR/remove_storage_markers.rs:9:16: 9:17 + _6 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:20: 10:6 +- StorageDead(_12); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 - StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 -- StorageDead(_4); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 -- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 -- StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2 - return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2 + _5 = const (); // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 + goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 } bb3: { -- StorageLive(_12); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 - _12 = ((_8 as Some).0: i32); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 -- StorageLive(_13); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10 - _13 = _12; // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10 - _6 = move _13; // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10 - _7 = const (); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10 -- StorageDead(_13); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10 -- StorageDead(_12); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 -- StorageDead(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 -- StorageDead(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 -- StorageDead(_7); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 -- StorageLive(_15); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 - _15 = _6; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageLive(_16); // scope 5 at $DIR/remove_storage_markers.rs:8:20: 10:6 -- StorageLive(_17); // scope 5 at $DIR/remove_storage_markers.rs:9:16: 9:17 - _17 = _15; // scope 5 at $DIR/remove_storage_markers.rs:9:16: 9:17 - _1 = Add(_1, move _17); // scope 5 at $DIR/remove_storage_markers.rs:9:9: 9:17 -- StorageDead(_17); // scope 5 at $DIR/remove_storage_markers.rs:9:16: 9:17 - _16 = const (); // scope 5 at $DIR/remove_storage_markers.rs:8:20: 10:6 -- StorageDead(_16); // scope 5 at $DIR/remove_storage_markers.rs:10:5: 10:6 - _5 = const (); // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 -- StorageDead(_15); // scope 3 at $DIR/remove_storage_markers.rs:10:5: 10:6 + _0 = const (); // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 +- StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 - StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 - goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 +- StorageDead(_4); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_2); // scope 1 at $DIR/remove_storage_markers.rs:10:5: 10:6 +- StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:11:1: 11:2 + return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2 } bb4: { -- StorageDead(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 -- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 - _11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 - switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageDead(_14); // scope 5 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:8:18: 8:19 + _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 + switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:8:14: 8:19 } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt index 28e0f1953e0..1c64ead9f26 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt @@ -5,7 +5,6 @@ 5| 1| 6| 1| let mut x = 0; 7| 11| for _ in 0..10 { - ^10 8| 10| match is_true { 9| | true => { 10| 10| continue; @@ -17,7 +16,6 @@ 16| 0| x = 3; 17| | } 18| 11| for _ in 0..10 { - ^10 19| 10| match is_true { 20| 0| false => { 21| 0| x = 1; @@ -29,7 +27,6 @@ 27| 0| x = 3; 28| | } 29| 11| for _ in 0..10 { - ^10 30| 10| match is_true { 31| 10| true => { 32| 10| x = 1; @@ -41,14 +38,12 @@ 38| 10| x = 3; 39| | } 40| 11| for _ in 0..10 { - ^10 41| 10| if is_true { 42| 10| continue; 43| 0| } 44| 0| x = 3; 45| | } 46| 11| for _ in 0..10 { - ^10 47| 10| match is_true { 48| 0| false => { 49| 0| x = 1; diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt index 31d3ddea8d9..6f5d1544fa0 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt @@ -40,7 +40,8 @@ 39| 30|} 40| | 41| 6|fn display<T: Display>(xs: &[T]) { - 42| 18| for x in xs { + 42| 24| for x in xs { + ^18 43| 18| print!("{}", x); 44| 18| } 45| 6| println!(); diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt index 5d572db7cc6..b7ad79a2484 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt @@ -17,7 +17,8 @@ 16| 0| } else { 17| 0| } 18| | - 19| 10| for i in 0..10 { + 19| 11| for i in 0..10 { + ^10 20| 10| if true { 21| 10| if false { 22| 0| while true {} @@ -43,7 +44,8 @@ 41| 1| write!(f, "cool")?; ^0 42| | } - 43| 10| for i in 0..10 { + 43| 11| for i in 0..10 { + ^10 44| 10| if false { 45| 0| } else { 46| 10| if false { diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt index 81b4c090a46..b9298213111 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt @@ -13,7 +13,7 @@ ^0 13| | 14| | for - 15| 2| _ + 15| | _ 16| | in 17| 3| 0..2 18| | { diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt index 9fca52451ed..0ad0180b761 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt @@ -14,7 +14,7 @@ 14| 1| countdown = 10 15| | ; 16| | for - 17| 6| _ + 17| | _ 18| | in 19| 6| 0..10 20| | { @@ -64,7 +64,7 @@ 63| 1| countdown = 10 64| | ; 65| | for - 66| 6| _ + 66| | _ 67| | in 68| 6| 0..10 69| | { diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.rs b/src/test/ui/borrowck/return-local-binding-from-desugaring.rs index b2dcd54ec2e..c6643edf5a9 100644 --- a/src/test/ui/borrowck/return-local-binding-from-desugaring.rs +++ b/src/test/ui/borrowck/return-local-binding-from-desugaring.rs @@ -27,7 +27,7 @@ where let key = f(x); result.entry(key).or_insert(Vec::new()).push(x); } - result //~ ERROR cannot return value referencing local binding + result //~ ERROR cannot return value referencing temporary value } fn main() {} diff --git a/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr b/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr index 293dbe62813..9f952542e18 100644 --- a/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr +++ b/src/test/ui/borrowck/return-local-binding-from-desugaring.stderr @@ -1,8 +1,8 @@ -error[E0515]: cannot return value referencing local binding +error[E0515]: cannot return value referencing temporary value --> $DIR/return-local-binding-from-desugaring.rs:30:5 | LL | for ref x in xs { - | -- local binding introduced here + | -- temporary value created here ... LL | result | ^^^^^^ returns a value referencing data owned by the current function diff --git a/src/test/ui/for/for-loop-unconstrained-element-type.stderr b/src/test/ui/for/for-loop-unconstrained-element-type.stderr index 0672014a929..580b135ac2d 100644 --- a/src/test/ui/for/for-loop-unconstrained-element-type.stderr +++ b/src/test/ui/for/for-loop-unconstrained-element-type.stderr @@ -1,8 +1,10 @@ error[E0282]: type annotations needed - --> $DIR/for-loop-unconstrained-element-type.rs:8:14 + --> $DIR/for-loop-unconstrained-element-type.rs:8:9 | LL | for i in Vec::new() { } - | ^^^^^^^^^^ the element type for this iterator is not specified + | ^ ---------- the element type for this iterator is not specified + | | + | cannot infer type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20261.stderr b/src/test/ui/issues/issue-20261.stderr index c6c3f32dfe7..6330364c92b 100644 --- a/src/test/ui/issues/issue-20261.stderr +++ b/src/test/ui/issues/issue-20261.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed for `&(_,)` +error[E0282]: type annotations needed for `(_,)` --> $DIR/issue-20261.rs:4:11 | LL | for (ref i,) in [].iter() { - | --------- the element type for this iterator is not specified + | --------- this method call resolves to `std::slice::Iter<'_, T>` LL | i.clone(); | ^^^^^ cannot infer type | diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs index 4fb805b37e0..ccaa6334856 100644 --- a/src/test/ui/issues/issue-33941.rs +++ b/src/test/ui/issues/issue-33941.rs @@ -3,5 +3,4 @@ use std::collections::HashMap; fn main() { for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch //~^ ERROR type mismatch - //~| ERROR type mismatch } diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index e7263148205..eb98a3a29a6 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -23,16 +23,6 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` -error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_` - --> $DIR/issue-33941.rs:4:14 - | -LL | for _ in HashMap::new().iter().cloned() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found tuple - | - = note: expected reference `&_` - found tuple `(&_, &_)` - = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/nll/dont-print-desugared.stderr b/src/test/ui/nll/dont-print-desugared.stderr index 88773def8b7..fad6121cbca 100644 --- a/src/test/ui/nll/dont-print-desugared.stderr +++ b/src/test/ui/nll/dont-print-desugared.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/dont-print-desugared.rs:4:10 | LL | for &ref mut x in s {} - | ^^^^^^^^^ cannot borrow as mutable through `&` reference + | ^^^^^^^^^ cannot borrow as mutable error[E0597]: `y` does not live long enough --> $DIR/dont-print-desugared.rs:17:16 diff --git a/src/test/ui/nll/issue-53773.stderr b/src/test/ui/nll/issue-53773.stderr index 11cd423295a..90cba2a145f 100644 --- a/src/test/ui/nll/issue-53773.stderr +++ b/src/test/ui/nll/issue-53773.stderr @@ -2,12 +2,10 @@ error[E0713]: borrow may still be in use when destructor runs --> $DIR/issue-53773.rs:41:22 | LL | members.push(child.raw); - | ^^^^^^^^^ + | -------------^^^^^^^^^- borrow later used here LL | LL | } | - here, drop of `child` needs exclusive access to `*child.raw`, because the type `C<'_>` implements the `Drop` trait -LL | members.len(); - | ------------- borrow later used here | = note: consider using a `let` binding to create a longer lived value diff --git a/src/test/ui/reachable/unreachable-loop-patterns.rs b/src/test/ui/reachable/unreachable-loop-patterns.rs index 4de29c3c3d7..e9cef5f47d4 100644 --- a/src/test/ui/reachable/unreachable-loop-patterns.rs +++ b/src/test/ui/reachable/unreachable-loop-patterns.rs @@ -17,5 +17,4 @@ impl Iterator for Void { fn main() { for _ in unimplemented!() as Void {} //~^ ERROR unreachable pattern - //~^^ ERROR unreachable pattern } diff --git a/src/test/ui/reachable/unreachable-loop-patterns.stderr b/src/test/ui/reachable/unreachable-loop-patterns.stderr index 680d22862d7..80ffa5d73f0 100644 --- a/src/test/ui/reachable/unreachable-loop-patterns.stderr +++ b/src/test/ui/reachable/unreachable-loop-patterns.stderr @@ -10,11 +10,5 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: unreachable pattern - --> $DIR/unreachable-loop-patterns.rs:18:14 - | -LL | for _ in unimplemented!() as Void {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs index 98e60f7ed85..6f213d7a699 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,6 +1,4 @@ -use super::{ - get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP, -}; +use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT_COUNTER_LOOP}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{get_enclosing_block, is_integer_const}; @@ -37,12 +35,10 @@ pub(super) fn check<'tcx>( then { let mut applicability = Applicability::MachineApplicable; - let for_span = get_span_of_entire_for_loop(expr); - span_lint_and_sugg( cx, EXPLICIT_COUNTER_LOOP, - for_span.with_hi(arg.span.hi()), + expr.span.with_hi(arg.span.hi()), &format!("the variable `{}` is used as a loop counter", name), "consider using", format!( diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index 72027a163af..2362b4b2067 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -1,4 +1,4 @@ -use super::{get_span_of_entire_for_loop, IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY}; +use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; @@ -86,7 +86,7 @@ pub(super) fn check<'tcx>( span_lint_and_sugg( cx, MANUAL_MEMCPY, - get_span_of_entire_for_loop(expr), + expr.span, "it looks like you're manually copying between slices", "try replacing the loop by", big_sugg, diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 5df1b796401..fd4881b2947 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -23,7 +23,7 @@ use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use utils::{get_span_of_entire_for_loop, make_iterator_snippet, IncrementVisitor, InitializeVisitor}; +use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; declare_clippy_lint! { /// ### What it does @@ -566,7 +566,15 @@ declare_lint_pass!(Loops => [ impl<'tcx> LateLintPass<'tcx> for Loops { #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(higher::ForLoop { pat, arg, body, span }) = higher::ForLoop::hir(expr) { + let for_loop = higher::ForLoop::hir(expr); + if let Some(higher::ForLoop { + pat, + arg, + body, + loop_id, + span, + }) = for_loop + { // we don't want to check expanded macros // this check is not at the top of the function // since higher::for_loop expressions are marked as expansions @@ -574,6 +582,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops { return; } check_for_loop(cx, pat, arg, body, expr, span); + if let ExprKind::Block(block, _) = body.kind { + never_loop::check(cx, block, loop_id, span, for_loop.as_ref()); + } } // we don't want to check expanded macros @@ -582,7 +593,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops { } // check for never_loop - never_loop::check(cx, expr); + if let ExprKind::Loop(block, ..) = expr.kind { + never_loop::check(cx, block, expr.hir_id, expr.span, None); + } // check for `loop { if let {} else break }` that could be `while let` // (also matches an explicit "match" instead of "if let") diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index c0fde5e5166..86b7d6d989a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -4,35 +4,41 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, LoopSource, Node, Pat, Stmt, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind}; use rustc_lint::LateContext; +use rustc_span::Span; use std::iter::{once, Iterator}; -pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Loop(block, _, source, _) = expr.kind { - match never_loop_block(block, expr.hir_id) { - NeverLoopResult::AlwaysBreak => { - span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| { - if_chain! { - if source == LoopSource::ForLoop; - if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1); - if let Some(ForLoop { arg: iterator, pat, span: for_span, .. }) = ForLoop::hir(parent_match); - then { - // Suggests using an `if let` instead. This is `Unspecified` because the - // loop may (probably) contain `break` statements which would be invalid - // in an `if let`. - diag.span_suggestion_verbose( - for_span.with_hi(iterator.span.hi()), - "if you need the first element of the iterator, try writing", - for_to_if_let_sugg(cx, iterator, pat), - Applicability::Unspecified, - ); - } - }; - }); - }, - NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (), - } +pub(super) fn check( + cx: &LateContext<'tcx>, + block: &'tcx Block<'_>, + loop_id: HirId, + span: Span, + for_loop: Option<&ForLoop<'_>>, +) { + match never_loop_block(block, loop_id) { + NeverLoopResult::AlwaysBreak => { + span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| { + if let Some(ForLoop { + arg: iterator, + pat, + span: for_span, + .. + }) = for_loop + { + // Suggests using an `if let` instead. This is `Unspecified` because the + // loop may (probably) contain `break` statements which would be invalid + // in an `if let`. + diag.span_suggestion_verbose( + for_span.with_hi(iterator.span.hi()), + "if you need the first element of the iterator, try writing", + for_to_if_let_sugg(cx, iterator, pat), + Applicability::Unspecified, + ); + } + }); + }, + NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (), } } diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index 0fd09ff7197..e39605f3e7d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -1,4 +1,4 @@ -use super::{get_span_of_entire_for_loop, SINGLE_ELEMENT_LOOP}; +use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::single_segment_path; use clippy_utils::source::{indent_of, snippet}; @@ -30,7 +30,6 @@ pub(super) fn check<'tcx>( if !block.stmts.is_empty(); then { - let for_span = get_span_of_entire_for_loop(expr); let mut block_str = snippet(cx, block.span, "..").into_owned(); block_str.remove(0); block_str.pop(); @@ -39,7 +38,7 @@ pub(super) fn check<'tcx>( span_lint_and_sugg( cx, SINGLE_ELEMENT_LOOP, - for_span, + expr.span, "for loop over a single element", "try", format!("{{\n{}let {} = &{};{}}}", " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)), target.name, list_item_name, block_str), diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index f9f515cc40a..c3939a66c6a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -7,7 +7,6 @@ use rustc_hir::HirIdMap; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; -use rustc_span::source_map::Span; use rustc_span::symbol::{sym, Symbol}; use std::iter::Iterator; @@ -300,17 +299,6 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } } -// this function assumes the given expression is a `for` loop. -pub(super) fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span { - // for some reason this is the only way to get the `Span` - // of the entire `for` loop - if let ExprKind::Match(_, arms, _) = &expr.kind { - arms[0].body.span - } else { - unreachable!() - } -} - /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the /// actual `Iterator` that the loop uses. pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String { diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 0f32cd9164e..78183add9cc 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -20,8 +20,8 @@ use rustc_span::symbol::sym; use clippy_utils::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, - iter_input_pats, last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq, + expr_path_res, get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, + last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq, }; declare_clippy_lint! { @@ -312,7 +312,6 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(an, .., name, None) = local.pat.kind; if let Some(init) = local.init; - if !higher::is_from_for_desugar(local); if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut; then { // use the macro callsite when the init span (but not the whole local span) diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index e7bc2446590..018e6d611db 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -1,16 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::last_path_segment; use rustc_hir::{ - intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatField, PatKind, - QPath, Stmt, StmtKind, + intravisit, Body, Expr, ExprKind, FnDecl, HirId, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use std::iter; declare_clippy_lint! { /// ### What it does @@ -87,43 +83,28 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]); impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Local(local) = stmt.kind { - if let Some(init) = &local.init { - if let Some(init_ty) = cx.typeck_results().node_type_opt(init.hir_id) { - let pat = &local.pat; - if in_external_macro(cx.sess(), pat.span) { - return; - } - let deref_possible = match local.source { - LocalSource::Normal => DerefPossible::Possible, - _ => DerefPossible::Impossible, - }; - apply_lint(cx, pat, init_ty, deref_possible); - } + if in_external_macro(cx.sess(), local.pat.span) { + return; } + let deref_possible = match local.source { + LocalSource::Normal => DerefPossible::Possible, + _ => DerefPossible::Impossible, + }; + apply_lint(cx, local.pat, deref_possible); } } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = expr.kind { - if let Some(expr_ty) = cx.typeck_results().node_type_opt(scrutinee.hir_id) { - 'pattern_checks: for arm in arms { - let pat = &arm.pat; - if in_external_macro(cx.sess(), pat.span) { - continue 'pattern_checks; - } - if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) { - break 'pattern_checks; - } + if let ExprKind::Match(_, arms, _) = expr.kind { + for arm in arms { + let pat = &arm.pat; + if apply_lint(cx, pat, DerefPossible::Possible) { + break; } } } - if let ExprKind::Let(let_pat, let_expr, _) = expr.kind { - if let Some(expr_ty) = cx.typeck_results().node_type_opt(let_expr.hir_id) { - if in_external_macro(cx.sess(), let_pat.span) { - return; - } - apply_lint(cx, let_pat, expr_ty, DerefPossible::Possible); - } + if let ExprKind::Let(let_pat, ..) = expr.kind { + apply_lint(cx, let_pat, DerefPossible::Possible); } } @@ -134,12 +115,10 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { _: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, _: Span, - hir_id: HirId, + _: HirId, ) { - if let Some(fn_sig) = cx.typeck_results().liberated_fn_sigs().get(hir_id) { - for (param, ty) in iter::zip(body.params, fn_sig.inputs()) { - apply_lint(cx, param.pat, ty, DerefPossible::Impossible); - } + for param in body.params { + apply_lint(cx, param.pat, DerefPossible::Impossible); } } } @@ -150,8 +129,8 @@ enum DerefPossible { Impossible, } -fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, expr_ty: Ty<'tcx>, deref_possible: DerefPossible) -> bool { - let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top); +fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, deref_possible: DerefPossible) -> bool { + let maybe_mismatch = find_first_mismatch(cx, pat); if let Some((span, mutability, level)) = maybe_mismatch { span_lint_and_help( cx, @@ -184,132 +163,32 @@ enum Level { } #[allow(rustc::usage_of_ty_tykind)] -fn find_first_mismatch<'tcx>( - cx: &LateContext<'tcx>, - pat: &Pat<'_>, - ty: Ty<'tcx>, - level: Level, -) -> Option<(Span, Mutability, Level)> { - if let PatKind::Ref(sub_pat, _) = pat.kind { - if let TyKind::Ref(_, sub_ty, _) = ty.kind() { - return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower); - } - } - - if let TyKind::Ref(_, _, mutability) = *ty.kind() { - if is_non_ref_pattern(&pat.kind) { - return Some((pat.span, mutability, level)); - } - } - - if let PatKind::Struct(ref qpath, field_pats, _) = pat.kind { - if let TyKind::Adt(adt_def, substs_ref) = ty.kind() { - if let Some(variant) = get_variant(adt_def, qpath) { - let field_defs = &variant.fields; - return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref); - } +fn find_first_mismatch<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> Option<(Span, Mutability, Level)> { + let mut result = None; + pat.walk(|p| { + if result.is_some() { + return false; } - } - - if let PatKind::TupleStruct(ref qpath, pats, _) = pat.kind { - if let TyKind::Adt(adt_def, substs_ref) = ty.kind() { - if let Some(variant) = get_variant(adt_def, qpath) { - let field_defs = &variant.fields; - let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref)); - return find_first_mismatch_in_tuple(cx, pats, ty_iter); - } - } - } - - if let PatKind::Tuple(pats, _) = pat.kind { - if let TyKind::Tuple(..) = ty.kind() { - return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields()); + if in_external_macro(cx.sess(), p.span) { + return true; } - } - - if let PatKind::Or(sub_pats) = pat.kind { - for pat in sub_pats { - let maybe_mismatch = find_first_mismatch(cx, pat, ty, level); - if let Some(mismatch) = maybe_mismatch { - return Some(mismatch); - } - } - } - - None -} - -fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> { - if adt_def.is_struct() { - if let Some(variant) = adt_def.variants.iter().next() { - return Some(variant); - } - } - - if adt_def.is_enum() { - let pat_ident = last_path_segment(qpath).ident; - for variant in &adt_def.variants { - if variant.ident == pat_ident { - return Some(variant); - } - } - } - - None -} - -fn find_first_mismatch_in_tuple<'tcx, I>( - cx: &LateContext<'tcx>, - pats: &[Pat<'_>], - ty_iter_src: I, -) -> Option<(Span, Mutability, Level)> -where - I: IntoIterator<Item = Ty<'tcx>>, -{ - let mut field_tys = ty_iter_src.into_iter(); - 'fields: for pat in pats { - let field_ty = if let Some(ty) = field_tys.next() { - ty - } else { - break 'fields; + let adjust_pat = match p.kind { + PatKind::Or([p, ..]) => p, + _ => p, }; - - let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower); - if let Some(mismatch) = maybe_mismatch { - return Some(mismatch); - } - } - - None -} - -fn find_first_mismatch_in_struct<'tcx>( - cx: &LateContext<'tcx>, - field_pats: &[PatField<'_>], - field_defs: &[FieldDef], - substs_ref: SubstsRef<'tcx>, -) -> Option<(Span, Mutability, Level)> { - for field_pat in field_pats { - 'definitions: for field_def in field_defs { - if field_pat.ident == field_def.ident { - let field_ty = field_def.ty(cx.tcx, substs_ref); - let pat = &field_pat.pat; - let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower); - if let Some(mismatch) = maybe_mismatch { - return Some(mismatch); + if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) { + if let [first, ..] = **adjustments { + if let ty::Ref(.., mutability) = *first.kind() { + let level = if p.hir_id == pat.hir_id { + Level::Top + } else { + Level::Lower + }; + result = Some((p.span, mutability, level)); } - break 'definitions; } } - } - - None -} - -fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool { - match pat_kind { - PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true, - PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)), - _ => false, - } + result.is_none() + }); + result } diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index fad647dfb26..b25a6e3375b 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::higher; use clippy_utils::source::snippet_with_macro_callsite; use rustc_errors::Applicability; use rustc_hir::{Stmt, StmtKind}; @@ -14,9 +13,6 @@ pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() { return; } - if higher::is_from_for_desugar(local) { - return; - } span_lint_and_then( cx, LET_UNIT_VALUE, diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 733cc97c845..7297265d08c 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -22,31 +22,31 @@ pub struct ForLoop<'tcx> { pub arg: &'tcx hir::Expr<'tcx>, /// `for` loop body pub body: &'tcx hir::Expr<'tcx>, + /// Compare this against `hir::Destination.target` + pub loop_id: HirId, /// entire `for` loop span pub span: Span, } impl<'tcx> ForLoop<'tcx> { - #[inline] /// Parses a desugared `for` loop pub fn hir(expr: &Expr<'tcx>) -> Option<Self> { if_chain! { - if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind; - if let Some(first_arm) = arms.get(0); - if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind; - if let Some(first_arg) = iterargs.get(0); - if iterargs.len() == 1 && arms.len() == 1 && first_arm.guard.is_none(); - if let hir::ExprKind::Loop(block, ..) = first_arm.body.kind; - if block.expr.is_none(); - if let [ _, _, ref let_stmt, ref body ] = *block.stmts; - if let hir::StmtKind::Local(local) = let_stmt.kind; - if let hir::StmtKind::Expr(body_expr) = body.kind; + if let hir::ExprKind::DropTemps(e) = expr.kind; + if let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind; + if let hir::ExprKind::Call(_, [arg]) = iterexpr.kind; + if let hir::ExprKind::Loop(block, ..) = arm.body.kind; + if let [stmt] = &*block.stmts; + if let hir::StmtKind::Expr(e) = stmt.kind; + if let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind; + if let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind; then { return Some(Self { - pat: &*local.pat, - arg: first_arg, - body: body_expr, - span: first_arm.span + pat: field.pat, + arg, + body: some_arm.body, + loop_id: arm.body.hir_id, + span: expr.span.ctxt().outer_expn_data().call_site, }); } } @@ -678,38 +678,6 @@ impl<'tcx> FormatArgsArg<'tcx> { } } -/// Checks if a `let` statement is from a `for` loop desugaring. -pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool { - // This will detect plain for-loops without an actual variable binding: - // - // ``` - // for x in some_vec { - // // do stuff - // } - // ``` - if_chain! { - if let Some(expr) = local.init; - if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind; - then { - return true; - } - } - - // This detects a variable binding in for loop to avoid `let_unit_value` - // lint (see issue #1964). - // - // ``` - // for _ in vec![()] { - // // anything - // } - // ``` - if let hir::LocalSource::ForLoopDesugar = local.source { - return true; - } - - false -} - /// A parsed `panic!` expansion pub struct PanicExpn<'tcx> { /// Span of `panic!(..)` diff --git a/src/tools/clippy/tests/ui/author/for_loop.stdout b/src/tools/clippy/tests/ui/author/for_loop.stdout index f1b4d4e096e..4d0e13c833f 100644 --- a/src/tools/clippy/tests/ui/author/for_loop.stdout +++ b/src/tools/clippy/tests/ui/author/for_loop.stdout @@ -11,11 +11,8 @@ if_chain! { // unimplemented: field checks if arms.len() == 1; if let ExprKind::Loop(ref body, ref label, LoopSource::ForLoop) = arms[0].body.kind; - if body.stmts.len() == 4; - if let StmtKind::Local(ref local) = body.stmts[0].kind; - if let PatKind::Binding(BindingAnnotation::Mutable, _, name, None) = local.pat.kind; - if name.as_str() == "__next"; - if let StmtKind::Expr(ref e, _) = body.stmts[1].kind + if body.stmts.len() == 1; + if let StmtKind::Expr(ref e, _) = body.stmts[0].kind if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind; if let ExprKind::Call(ref func1, ref args1) = expr2.kind; if let ExprKind::Path(ref path2) = func1.kind; @@ -25,39 +22,27 @@ if_chain! { if let ExprKind::Path(ref path3) = inner.kind; if match_qpath(path3, &["iter"]); if arms1.len() == 2; - if let ExprKind::Assign(ref target, ref value, ref _span) = arms1[0].body.kind; - if let ExprKind::Path(ref path4) = target.kind; - if match_qpath(path4, &["__next"]); - if let ExprKind::Path(ref path5) = value.kind; - if match_qpath(path5, &["val"]); - if let PatKind::Struct(ref path6, ref fields1, false) = arms1[0].pat.kind; - if matches!(path6, QPath::LangItem(LangItem::OptionSome, _)); - if fields1.len() == 1; - // unimplemented: field checks - if let ExprKind::Break(ref destination, None) = arms1[1].body.kind; - if let PatKind::Struct(ref path7, ref fields2, false) = arms1[1].pat.kind; - if matches!(path7, QPath::LangItem(LangItem::OptionNone, _)); - if fields2.len() == 0; + if let ExprKind::Break(ref destination, None) = arms1[0].body.kind; + if let PatKind::Struct(ref path4, ref fields1, false) = arms1[0].pat.kind; + if matches!(path4, QPath::LangItem(LangItem::OptionNone, _)); + if fields1.len() == 0; // unimplemented: field checks - if let StmtKind::Local(ref local1) = body.stmts[2].kind; - if let Some(ref init) = local1.init; - if let ExprKind::Path(ref path8) = init.kind; - if match_qpath(path8, &["__next"]); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind; - if name1.as_str() == "y"; - if let StmtKind::Expr(ref e1, _) = body.stmts[3].kind - if let ExprKind::Block(ref block) = e1.kind; + if let ExprKind::Block(ref block) = arms1[1].body.kind; if block.stmts.len() == 1; - if let StmtKind::Local(ref local2) = block.stmts[0].kind; - if let Some(ref init1) = local2.init; - if let ExprKind::Path(ref path9) = init1.kind; - if match_qpath(path9, &["y"]); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name2, None) = local2.pat.kind; - if name2.as_str() == "z"; + if let StmtKind::Local(ref local) = block.stmts[0].kind; + if let Some(ref init) = local.init; + if let ExprKind::Path(ref path5) = init.kind; + if match_qpath(path5, &["y"]); + if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind; + if name.as_str() == "z"; if block.expr.is_none(); + if let PatKind::Struct(ref path6, ref fields2, false) = arms1[1].pat.kind; + if matches!(path6, QPath::LangItem(LangItem::OptionSome, _)); + if fields2.len() == 1; + // unimplemented: field checks if body.expr.is_none(); - if let PatKind::Binding(BindingAnnotation::Mutable, _, name3, None) = arms[0].pat.kind; - if name3.as_str() == "iter"; + if let PatKind::Binding(BindingAnnotation::Mutable, _, name1, None) = arms[0].pat.kind; + if name1.as_str() == "iter"; then { // report your lint here } |
