From 070c83d5a96d26240824abdb3c38ecdb860710f5 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 5 Aug 2019 11:32:27 +0200 Subject: [PATCH 1/8] add contains benchmarks --- .../tiny_list/tests.rs | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/librustc_data_structures/tiny_list/tests.rs b/src/librustc_data_structures/tiny_list/tests.rs index 8374659e1e6..0142631590c 100644 --- a/src/librustc_data_structures/tiny_list/tests.rs +++ b/src/librustc_data_structures/tiny_list/tests.rs @@ -1,7 +1,7 @@ use super::*; extern crate test; -use test::Bencher; +use test::{Bencher, black_box}; #[test] fn test_contains_and_insert() { @@ -98,36 +98,59 @@ fn test_remove_single() { #[bench] fn bench_insert_empty(b: &mut Bencher) { b.iter(|| { - let mut list = TinyList::new(); + let mut list = black_box(TinyList::new()); list.insert(1); + list }) } #[bench] fn bench_insert_one(b: &mut Bencher) { b.iter(|| { - let mut list = TinyList::new_single(0); + let mut list = black_box(TinyList::new_single(0)); list.insert(1); + list }) } +#[bench] +fn bench_contains_empty(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new()).contains(&1) + }); +} + +#[bench] +fn bench_contains_unknown(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new_single(0)).contains(&1) + }); +} + +#[bench] +fn bench_contains_one(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new_single(1)).contains(&1) + }); +} + #[bench] fn bench_remove_empty(b: &mut Bencher) { b.iter(|| { - TinyList::new().remove(&1) + black_box(TinyList::new()).remove(&1) }); } #[bench] fn bench_remove_unknown(b: &mut Bencher) { b.iter(|| { - TinyList::new_single(0).remove(&1) + black_box(TinyList::new_single(0)).remove(&1) }); } #[bench] fn bench_remove_one(b: &mut Bencher) { b.iter(|| { - TinyList::new_single(1).remove(&1) + black_box(TinyList::new_single(1)).remove(&1) }); } From 45f14a8c9026b33dc278000a5fc120e9667806ff Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 17 Jul 2019 08:19:29 +0200 Subject: [PATCH 2/8] refactor `len` and `contains` to iterate instead of recurse --- src/librustc_data_structures/tiny_list.rs | 56 +++++++---------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index 1c0d9360f25..ea771d9f20f 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -20,7 +20,6 @@ pub struct TinyList { } impl TinyList { - #[inline] pub fn new() -> TinyList { TinyList { @@ -60,20 +59,24 @@ impl TinyList { #[inline] pub fn contains(&self, data: &T) -> bool { - if let Some(ref head) = self.head { - head.contains(data) - } else { - false + let mut elem = self.head.as_ref(); + while let Some(ref e) = elem { + if &e.data == data { + return true; + } + elem = e.next.as_ref().map(|e| &**e); } + false } #[inline] pub fn len(&self) -> usize { - if let Some(ref head) = self.head { - head.len() - } else { - 0 + let (mut elem, mut count) = (self.head.as_ref(), 0); + while let Some(ref e) = elem { + count += 1; + elem = e.next.as_ref().map(|e| &**e); } + count } } @@ -84,40 +87,13 @@ struct Element { } impl Element { - fn remove_next(&mut self, data: &T) -> bool { - let new_next = if let Some(ref mut next) = self.next { - if next.data != *data { - return next.remove_next(data) - } else { - next.next.take() - } - } else { - return false + let new_next = match self.next { + Some(ref mut next) if next.data == *data => next.next.take(), + Some(ref mut next) => return next.remove_next(data), + None => return false, }; - self.next = new_next; - true } - - fn len(&self) -> usize { - if let Some(ref next) = self.next { - 1 + next.len() - } else { - 1 - } - } - - fn contains(&self, data: &T) -> bool { - if self.data == *data { - return true - } - - if let Some(ref next) = self.next { - next.contains(data) - } else { - false - } - } } From 1acb53753be395f6b5bd880617ddceaa4bfadcfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 22 Aug 2019 10:38:09 -0700 Subject: [PATCH 3/8] Do not suggest `.try_into()` on `i32::from(x)` --- src/librustc_typeck/check/demand.rs | 24 +++++++++++++++++++ .../mismatched-types-numeric-from.rs | 3 +++ .../mismatched-types-numeric-from.stderr | 9 +++++++ 3 files changed, 36 insertions(+) create mode 100644 src/test/ui/suggestions/mismatched-types-numeric-from.rs create mode 100644 src/test/ui/suggestions/mismatched-types-numeric-from.stderr diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index de5ba8bc8eb..0efc433341c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -587,6 +587,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } } + if let hir::ExprKind::Call(path, args) = &expr.node { + if let ( + hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), + 1, + ) = (&path.node, args.len()) { + // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697). + if let ( + hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), + sym::from, + ) = (&base_ty.node, path_segment.ident.name) { + if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() { + match ident.name { + sym::i128 | sym::i64 | sym::i32 | sym::i16 | sym::i8 | + sym::u128 | sym::u64 | sym::u32 | sym::u16 | sym::u8 | + sym::isize | sym::usize + if base_ty_path.segments.len() == 1 => { + return false; + } + _ => {} + } + } + } + } + } let msg = format!("you can convert an `{}` to `{}`", checked_ty, expected_ty); let cast_msg = format!("you can cast an `{} to `{}`", checked_ty, expected_ty); diff --git a/src/test/ui/suggestions/mismatched-types-numeric-from.rs b/src/test/ui/suggestions/mismatched-types-numeric-from.rs new file mode 100644 index 00000000000..56549da9c73 --- /dev/null +++ b/src/test/ui/suggestions/mismatched-types-numeric-from.rs @@ -0,0 +1,3 @@ +fn main() { + let _: u32 = i32::from(0_u8); //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/mismatched-types-numeric-from.stderr b/src/test/ui/suggestions/mismatched-types-numeric-from.stderr new file mode 100644 index 00000000000..223b6747322 --- /dev/null +++ b/src/test/ui/suggestions/mismatched-types-numeric-from.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/mismatched-types-numeric-from.rs:2:18 + | +LL | let _: u32 = i32::from(0_u8); + | ^^^^^^^^^^^^^^^ expected u32, found i32 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 73e3508bb84bec2911f56e5c2463eee3688cf8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 23 Aug 2019 11:14:11 -0700 Subject: [PATCH 4/8] Suggest calling closure with resolved return type when appropriate --- src/librustc/ty/sty.rs | 3 +- src/librustc_typeck/check/coercion.rs | 13 +- src/librustc_typeck/check/mod.rs | 136 ++++++++++-------- .../fn-or-tuple-struct-without-args.rs | 2 + .../fn-or-tuple-struct-without-args.stderr | 16 ++- 5 files changed, 106 insertions(+), 64 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index da66fdf5b1b..7b7e2b8bfbd 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -385,7 +385,8 @@ impl<'tcx> ClosureSubsts<'tcx> { let ty = self.closure_sig_ty(def_id, tcx); match ty.sty { ty::FnPtr(sig) => sig, - _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty), + ty::Infer(_) | ty::Error => ty::Binder::dummy(FnSig::fake()), // ignore errors + _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty.sty), } } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 4edb6ad8931..61b9c2a15ba 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -799,12 +799,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. /// The expressions *must not* have any pre-existing adjustments. - pub fn try_coerce(&self, - expr: &hir::Expr, - expr_ty: Ty<'tcx>, - target: Ty<'tcx>, - allow_two_phase: AllowTwoPhase) - -> RelateResult<'tcx, Ty<'tcx>> { + pub fn try_coerce( + &self, + expr: &hir::Expr, + expr_ty: Ty<'tcx>, + target: Ty<'tcx>, + allow_two_phase: AllowTwoPhase, + ) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c7ac83e82e..d92ce29f284 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3917,75 +3917,99 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - match found.sty { - ty::FnDef(..) | ty::FnPtr(_) => {} - _ => return false, - } let hir = self.tcx.hir(); + let (def_id, sig) = match found.sty { + ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), + ty::Closure(def_id, substs) => { + // We don't use `closure_sig` to account for malformed closures like + // `|_: [_; continue]| {}` and instead we don't suggest anything. + let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx); + (def_id, match closure_sig_ty.sty { + ty::FnPtr(sig) => sig, + _ => return false, + }) + } + _ => return false, + }; - let sig = found.fn_sig(self.tcx); let sig = self .replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig) .0; let sig = self.normalize_associated_types_in(expr.span, &sig); - if let Ok(_) = self.try_coerce(expr, sig.output(), expected, AllowTwoPhase::No) { + if self.can_coerce(sig.output(), expected) { let (mut sugg_call, applicability) = if sig.inputs().is_empty() { (String::new(), Applicability::MachineApplicable) } else { ("...".to_string(), Applicability::HasPlaceholders) }; let mut msg = "call this function"; - if let ty::FnDef(def_id, ..) = found.sty { - match hir.get_if_local(def_id) { - Some(Node::Item(hir::Item { - node: ItemKind::Fn(.., body_id), - .. - })) | - Some(Node::ImplItem(hir::ImplItem { - node: hir::ImplItemKind::Method(_, body_id), - .. - })) | - Some(Node::TraitItem(hir::TraitItem { - node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)), - .. - })) => { - let body = hir.body(*body_id); - sugg_call = body.arguments.iter() - .map(|arg| match &arg.pat.node { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => ident.to_string(), - _ => "_".to_string(), - }).collect::>().join(", "); - } - Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { - sugg_call = fields.iter().map(|_| "_").collect::>().join(", "); - match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) { - Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { - msg = "instantiate this tuple variant"; - } - Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => { - msg = "instantiate this tuple struct"; - } - _ => {} - } - } - Some(Node::ForeignItem(hir::ForeignItem { - node: hir::ForeignItemKind::Fn(_, idents, _), - .. - })) | - Some(Node::TraitItem(hir::TraitItem { - node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)), - .. - })) => sugg_call = idents.iter() - .map(|ident| if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - }).collect::>() - .join(", "), - _ => {} + match hir.get_if_local(def_id) { + Some(Node::Item(hir::Item { + node: ItemKind::Fn(.., body_id), + .. + })) | + Some(Node::ImplItem(hir::ImplItem { + node: hir::ImplItemKind::Method(_, body_id), + .. + })) | + Some(Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)), + .. + })) => { + let body = hir.body(*body_id); + sugg_call = body.arguments.iter() + .map(|arg| match &arg.pat.node { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "); } - }; + Some(Node::Expr(hir::Expr { + node: ExprKind::Closure(_, _, body_id, closure_span, _), + span: full_closure_span, + .. + })) => { + if *full_closure_span == expr.span { + return false; + } + err.span_label(*closure_span, "closure defined here"); + msg = "call this closure"; + let body = hir.body(*body_id); + sugg_call = body.arguments.iter() + .map(|arg| match &arg.pat.node { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "); + } + Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { + sugg_call = fields.iter().map(|_| "_").collect::>().join(", "); + match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) { + Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { + msg = "instantiate this tuple variant"; + } + Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => { + msg = "instantiate this tuple struct"; + } + _ => {} + } + } + Some(Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(_, idents, _), + .. + })) | + Some(Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)), + .. + })) => sugg_call = idents.iter() + .map(|ident| if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + }).collect::>() + .join(", "), + _ => {} + } if let Ok(code) = self.sess().source_map().span_to_snippet(expr.span) { err.span_suggestion( expr.span, diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs index 9b6b1074817..dd5af3e344c 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs @@ -42,4 +42,6 @@ fn main() { let _: usize = X::bal; //~ ERROR mismatched types let _: usize = X.ban; //~ ERROR attempted to take value of method let _: usize = X.bal; //~ ERROR attempted to take value of method + let closure = || 42; + let _: usize = closure; //~ ERROR mismatched types } diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 0686b56f97d..28b331bdbdc 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -214,7 +214,21 @@ error[E0615]: attempted to take value of method `bal` on type `X` LL | let _: usize = X.bal; | ^^^ help: use parentheses to call the method: `bal()` -error: aborting due to 16 previous errors +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:46:20 + | +LL | let closure = || 42; + | -- closure defined here +LL | let _: usize = closure; + | ^^^^^^^ + | | + | expected usize, found closure + | help: use parentheses to call this closure: `closure()` + | + = note: expected type `usize` + found type `[closure@$DIR/fn-or-tuple-struct-without-args.rs:45:19: 45:24]` + +error: aborting due to 17 previous errors Some errors have detailed explanations: E0308, E0423, E0615. For more information about an error, try `rustc --explain E0308`. From 7dff647d23103f1de29df89c0714eddec6c0a57b Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 24 Aug 2019 02:23:56 +0200 Subject: [PATCH 5/8] Ensure miri can do bit ops on pointer values --- src/librustc_mir/interpret/intrinsics.rs | 13 ++++++++----- src/librustc_mir/interpret/operand.rs | 9 ++++----- src/librustc_mir/interpret/traits.rs | 6 ++++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 4c86c53256e..334f1ea1a69 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -95,7 +95,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | "bitreverse" => { let ty = substs.type_at(0); let layout_of = self.layout_of(ty)?; - let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?; + let val = self.read_scalar(args[0])?.not_undef()?; + let bits = self.force_bits(val, layout_of.size)?; let kind = match layout_of.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => throw_unsup!(TypeNotPrimitive(ty)), @@ -149,7 +150,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // term since the sign of the second term can be inferred from this and // the fact that the operation has overflowed (if either is 0 no // overflow can occur) - let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; + let first_term: u128 = self.force_bits(l.to_scalar()?, l.layout.size)?; let first_term_positive = first_term & (1 << (num_bits-1)) == 0; if first_term_positive { // Negative overflow not possible since the positive first term @@ -187,7 +188,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?; if overflowed { let layout = self.layout_of(substs.type_at(0))?; - let r_val = r.to_scalar()?.to_bits(layout.size)?; + let r_val = self.force_bits(r.to_scalar()?, layout.size)?; throw_ub_format!("Overflowing shift by {} in `{}`", r_val, intrinsic_name); } self.write_scalar(val, dest)?; @@ -196,8 +197,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) let layout = self.layout_of(substs.type_at(0))?; - let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?; - let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?; + let val = self.read_scalar(args[0])?.not_undef()?; + let val_bits = self.force_bits(val, layout.size)?; + let raw_shift = self.read_scalar(args[1])?.not_undef()?; + let raw_shift_bits = self.force_bits(raw_shift, layout.size)?; let width_bits = layout.size.bits() as u128; let shift_bits = raw_shift_bits % width_bits; let inv_shift_bits = (width_bits - shift_bits) % width_bits; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 7a545e8ad6f..b5aab992e3a 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -629,11 +629,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // post-process Ok(match *discr_kind { layout::DiscriminantKind::Tag => { - let bits_discr = match raw_discr.to_bits(discr_val.layout.size) { - Ok(raw_discr) => raw_discr, - Err(_) => - throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag())), - }; + let bits_discr = raw_discr + .not_undef() + .and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size)) + .map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?; let real_discr = if discr_val.layout.ty.is_signed() { // going from layout tag type to typeck discriminant type // requires first sign extending with the layout discriminant diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index a2fc75739ff..34a10de7de7 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -144,11 +144,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size = alloc.read_ptr_sized( self, vtable.offset(pointer_size, self)? - )?.to_bits(pointer_size)? as u64; + )?.not_undef()?; + let size = self.force_bits(size, pointer_size)? as u64; let align = alloc.read_ptr_sized( self, vtable.offset(pointer_size * 2, self)?, - )?.to_bits(pointer_size)? as u64; + )?.not_undef()?; + let align = self.force_bits(align, pointer_size)? as u64; Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap())) } } From 6a3d51731408708cbc6a6e4e2683da8df7326007 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 24 Aug 2019 13:54:40 -0300 Subject: [PATCH 6/8] Modifies how Arg, Arm, Field, FieldPattern and Variant are visited Part of the necessary work to accomplish #63468. --- src/librustc/hir/map/def_collector.rs | 7 +- src/librustc/lint/context.rs | 35 +++---- src/librustc/lint/mod.rs | 36 ++----- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/nonstandard_style.rs | 5 +- src/librustc_passes/ast_validation.rs | 3 +- src/librustc_passes/hir_stats.rs | 7 +- src/libsyntax/ext/expand.rs | 10 +- src/libsyntax/mut_visit.rs | 126 +++++++++++++++---------- src/libsyntax/util/node_count.rs | 7 +- src/libsyntax/visit.rs | 54 ++++++----- 11 files changed, 147 insertions(+), 145 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index d725afa4052..17bcb1d0859 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -154,7 +154,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { }); } - fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &'a Variant) { let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.as_interned_str()), v.span); @@ -162,12 +162,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { if let Some(ctor_hir_id) = v.data.ctor_id() { this.create_def(ctor_hir_id, DefPathData::Ctor, v.span); } - visit::walk_variant(this, v, g, item_id) + visit::walk_variant(this, v) }); } - fn visit_variant_data(&mut self, data: &'a VariantData, _: Ident, - _: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, data: &'a VariantData) { for (index, field) in data.fields().iter().enumerate() { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| sym::integer(index)); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6801fa8d8db..8126db14292 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1040,13 +1040,13 @@ for LateContextAndPass<'a, 'tcx, T> { fn visit_variant_data(&mut self, s: &'tcx hir::VariantData, - name: ast::Name, - g: &'tcx hir::Generics, - item_id: hir::HirId, + _: ast::Name, + _: &'tcx hir::Generics, + _: hir::HirId, _: Span) { - lint_callback!(self, check_struct_def, s, name, g, item_id); + lint_callback!(self, check_struct_def, s); hir_visit::walk_struct_def(self, s); - lint_callback!(self, check_struct_def_post, s, name, g, item_id); + lint_callback!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { @@ -1061,9 +1061,9 @@ for LateContextAndPass<'a, 'tcx, T> { g: &'tcx hir::Generics, item_id: hir::HirId) { self.with_lint_attrs(v.id, &v.attrs, |cx| { - lint_callback!(cx, check_variant, v, g); + lint_callback!(cx, check_variant, v); hir_visit::walk_variant(cx, v, g, item_id); - lint_callback!(cx, check_variant_post, v, g); + lint_callback!(cx, check_variant_post, v); }) } @@ -1214,18 +1214,13 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_fn_post, fk, decl, span, id); } - fn visit_variant_data(&mut self, - s: &'a ast::VariantData, - ident: ast::Ident, - g: &'a ast::Generics, - item_id: ast::NodeId, - _: Span) { - run_early_pass!(self, check_struct_def, s, ident, g, item_id); + fn visit_variant_data(&mut self, s: &'a ast::VariantData) { + run_early_pass!(self, check_struct_def, s); if let Some(ctor_hir_id) = s.ctor_id() { self.check_id(ctor_hir_id); } ast_visit::walk_struct_def(self, s); - run_early_pass!(self, check_struct_def_post, s, ident, g, item_id); + run_early_pass!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'a ast::StructField) { @@ -1235,11 +1230,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) } - fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { - self.with_lint_attrs(item_id, &v.attrs, |cx| { - run_early_pass!(cx, check_variant, v, g); - ast_visit::walk_variant(cx, v, g, item_id); - run_early_pass!(cx, check_variant_post, v, g); + fn visit_variant(&mut self, v: &'a ast::Variant) { + self.with_lint_attrs(v.id, &v.attrs, |cx| { + run_early_pass!(cx, check_variant, v); + ast_visit::walk_variant(cx, v); + run_early_pass!(cx, check_variant_post, v); }) } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 2b58627cdea..7e2707b98d5 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -248,21 +248,11 @@ macro_rules! late_lint_methods { fn check_trait_item_post(a: &$hir hir::TraitItem); fn check_impl_item(a: &$hir hir::ImplItem); fn check_impl_item_post(a: &$hir hir::ImplItem); - fn check_struct_def( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); - fn check_struct_def_post( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); + fn check_struct_def(a: &$hir hir::VariantData); + fn check_struct_def_post(a: &$hir hir::VariantData); fn check_struct_field(a: &$hir hir::StructField); - fn check_variant(a: &$hir hir::Variant, b: &$hir hir::Generics); - fn check_variant_post(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_variant(a: &$hir hir::Variant); + fn check_variant_post(a: &$hir hir::Variant); fn check_lifetime(a: &$hir hir::Lifetime); fn check_path(a: &$hir hir::Path, b: hir::HirId); fn check_attribute(a: &$hir ast::Attribute); @@ -395,21 +385,11 @@ macro_rules! early_lint_methods { fn check_trait_item_post(a: &ast::TraitItem); fn check_impl_item(a: &ast::ImplItem); fn check_impl_item_post(a: &ast::ImplItem); - fn check_struct_def( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); - fn check_struct_def_post( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); + fn check_struct_def(a: &ast::VariantData); + fn check_struct_def_post(a: &ast::VariantData); fn check_struct_field(a: &ast::StructField); - fn check_variant(a: &ast::Variant, b: &ast::Generics); - fn check_variant_post(a: &ast::Variant, b: &ast::Generics); + fn check_variant(a: &ast::Variant); + fn check_variant_post(a: &ast::Variant); fn check_lifetime(a: &ast::Lifetime); fn check_path(a: &ast::Path, b: ast::NodeId); fn check_attribute(a: &ast::Attribute); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ce7681c974a..d3c94060e27 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -482,7 +482,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } } - fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) { + fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant) { self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index acd17f76632..bb6119d0ff2 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -146,7 +146,7 @@ impl EarlyLintPass for NonCamelCaseTypes { } } - fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant, _: &ast::Generics) { + fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) { self.check_case(cx, "variant", &v.ident); } @@ -350,9 +350,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { &mut self, cx: &LateContext<'_, '_>, s: &hir::VariantData, - _: ast::Name, - _: &hir::Generics, - _: hir::HirId, ) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.ident); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bd46ca4779a..5b78727fdd5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -813,8 +813,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_poly_trait_ref(self, t, m); } - fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident, - _: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'a VariantData) { self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 8fba3256ec4..7e03df5b75b 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -334,12 +334,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_struct_field(self, s) } - fn visit_variant(&mut self, - v: &'v ast::Variant, - g: &'v ast::Generics, - item_id: NodeId) { + fn visit_variant(&mut self, v: &'v ast::Variant) { self.record("Variant", Id::None, v); - ast_visit::walk_variant(self, v, g, item_id) + ast_visit::walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 72f2c1375e7..92b48ed62cd 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1210,9 +1210,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - fn visit_generic_params(&mut self, params: &mut Vec) { - self.cfg.configure_generic_params(params); - noop_visit_generic_params(params, self); + fn flat_map_generic_param( + &mut self, + param: ast::GenericParam + ) -> SmallVec<[ast::GenericParam; 1]> + { + let param = configure!(self, param); + noop_flat_map_generic_param(param, self) } fn visit_attribute(&mut self, at: &mut ast::Attribute) { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 9785f8e2de0..414d234e434 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -98,8 +98,8 @@ pub trait MutVisitor: Sized { noop_visit_fn_header(header, self); } - fn visit_struct_field(&mut self, sf: &mut StructField) { - noop_visit_struct_field(sf, self); + fn flat_map_struct_field(&mut self, sf: StructField) -> SmallVec<[StructField; 1]> { + noop_flat_map_struct_field(sf, self) } fn visit_item_kind(&mut self, i: &mut ItemKind) { @@ -130,8 +130,8 @@ pub trait MutVisitor: Sized { noop_flat_map_stmt(s, self) } - fn visit_arm(&mut self, a: &mut Arm) { - noop_visit_arm(a, self); + fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { + noop_flat_map_arm(arm, self) } fn visit_pat(&mut self, p: &mut P) { @@ -174,8 +174,8 @@ pub trait MutVisitor: Sized { noop_visit_foreign_mod(nm, self); } - fn visit_variant(&mut self, v: &mut Variant) { - noop_visit_variant(v, self); + fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { + noop_flat_map_variant(v, self) } fn visit_ident(&mut self, i: &mut Ident) { @@ -225,8 +225,8 @@ pub trait MutVisitor: Sized { noop_visit_attribute(at, self); } - fn visit_arg(&mut self, a: &mut Arg) { - noop_visit_arg(a, self); + fn flat_map_arg(&mut self, arg: Arg) -> SmallVec<[Arg; 1]> { + noop_flat_map_arg(arg, self) } fn visit_generics(&mut self, generics: &mut Generics) { @@ -245,12 +245,8 @@ pub trait MutVisitor: Sized { noop_visit_variant_data(vdata, self); } - fn visit_generic_param(&mut self, param: &mut GenericParam) { - noop_visit_generic_param(param, self); - } - - fn visit_generic_params(&mut self, params: &mut Vec) { - noop_visit_generic_params(params, self); + fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { + noop_flat_map_generic_param(param, self) } fn visit_tt(&mut self, tt: &mut TokenTree) { @@ -277,8 +273,8 @@ pub trait MutVisitor: Sized { noop_visit_mt(mt, self); } - fn visit_field(&mut self, field: &mut Field) { - noop_visit_field(field, self); + fn flat_map_field(&mut self, f: Field) -> SmallVec<[Field; 1]> { + noop_flat_map_field(f, self) } fn visit_where_clause(&mut self, where_clause: &mut WhereClause) { @@ -300,6 +296,10 @@ pub trait MutVisitor: Sized { fn visit_span(&mut self, _sp: &mut Span) { // Do nothing. } + + fn flat_map_field_pattern(&mut self, fp: FieldPat) -> SmallVec<[FieldPat; 1]> { + noop_flat_map_field_pattern(fp, self) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -362,6 +362,26 @@ pub fn visit_method_sig(MethodSig { header, decl }: &mut MethodSi vis.visit_fn_decl(decl); } +pub fn noop_flat_map_field_pattern( + mut fp: FieldPat, + vis: &mut T, +) -> SmallVec<[FieldPat; 1]> { + let FieldPat { + attrs, + id, + ident, + is_shorthand: _, + pat, + span, + } = &mut fp; + vis.visit_id(id); + vis.visit_ident(ident); + vis.visit_pat(pat); + vis.visit_span(span); + visit_thin_attrs(attrs, vis); + smallvec![fp] +} + pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { let UseTree { prefix, kind, span } = use_tree; vis.visit_path(prefix); @@ -382,16 +402,18 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arm( - Arm { attrs, pats, guard, body, span, id }: &mut Arm, +pub fn noop_flat_map_arm( + mut arm: Arm, vis: &mut T, -) { +) -> SmallVec<[Arm; 1]> { + let Arm { attrs, pats, guard, body, span, id } = &mut arm; visit_attrs(attrs, vis); vis.visit_id(id); visit_vec(pats, |pat| vis.visit_pat(pat)); visit_opt(guard, |guard| vis.visit_expr(guard)); vis.visit_expr(body); vis.visit_span(span); + smallvec![arm] } pub fn noop_visit_ty_constraint( @@ -425,7 +447,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } TyKind::BareFn(bft) => { let BareFnTy { unsafety: _, abi: _, generic_params, decl } = bft.deref_mut(); - vis.visit_generic_params(generic_params); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); } TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)), @@ -455,14 +477,17 @@ pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } -pub fn noop_visit_variant(variant: &mut Variant, vis: &mut T) { - let Variant { ident, attrs, id, data, disr_expr, span } = variant; +pub fn noop_flat_map_variant(mut variant: Variant, vis: &mut T) + -> SmallVec<[Variant; 1]> +{ + let Variant { ident, attrs, id, data, disr_expr, span } = &mut variant; vis.visit_ident(ident); visit_attrs(attrs, vis); vis.visit_id(id); vis.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr)); vis.visit_span(span); + smallvec![variant] } pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: &mut T) { @@ -562,12 +587,14 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { attrs, id, pat, span, ty }: &mut Arg, vis: &mut T) { +pub fn noop_flat_map_arg(mut arg: Arg, vis: &mut T) -> SmallVec<[Arg; 1]> { + let Arg { attrs, id, pat, span, ty } = &mut arg; vis.visit_id(id); visit_thin_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_span(span); vis.visit_ty(ty); + smallvec![arg] } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { @@ -693,7 +720,7 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { let FnDecl { inputs, output, c_variadic: _ } = decl.deref_mut(); - visit_vec(inputs, |input| vis.visit_arg(input)); + inputs.flat_map_in_place(|arg| vis.flat_map_arg(arg)); match output { FunctionRetTy::Default(span) => vis.visit_span(span), FunctionRetTy::Ty(ty) => vis.visit_ty(ty), @@ -707,8 +734,12 @@ pub fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) } } -pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &mut T) { - let GenericParam { id, ident, attrs, bounds, kind } = param; +pub fn noop_flat_map_generic_param( + mut param: GenericParam, + vis: &mut T +) -> SmallVec<[GenericParam; 1]> +{ + let GenericParam { id, ident, attrs, bounds, kind } = &mut param; vis.visit_id(id); vis.visit_ident(ident); visit_thin_attrs(attrs, vis); @@ -722,10 +753,7 @@ pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &m vis.visit_ty(ty); } } -} - -pub fn noop_visit_generic_params(params: &mut Vec, vis: &mut T){ - visit_vec(params, |param| vis.visit_generic_param(param)); + smallvec![param] } pub fn noop_visit_label(Label { ident }: &mut Label, vis: &mut T) { @@ -739,7 +767,7 @@ fn noop_visit_lifetime(Lifetime { id, ident }: &mut Lifetime, vis pub fn noop_visit_generics(generics: &mut Generics, vis: &mut T) { let Generics { params, where_clause, span } = generics; - vis.visit_generic_params(params); + params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_where_clause(where_clause); vis.visit_span(span); } @@ -755,7 +783,7 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: WherePredicate::BoundPredicate(bp) => { let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; vis.visit_span(span); - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_ty(bounded_ty); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } @@ -777,9 +805,11 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { match vdata { - VariantData::Struct(fields, ..) => visit_vec(fields, |field| vis.visit_struct_field(field)), + VariantData::Struct(fields, ..) => { + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); + }, VariantData::Tuple(fields, id) => { - visit_vec(fields, |field| vis.visit_struct_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); vis.visit_id(id); }, VariantData::Unit(id) => vis.visit_id(id), @@ -793,28 +823,32 @@ pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut Trait pub fn noop_visit_poly_trait_ref(p: &mut PolyTraitRef, vis: &mut T) { let PolyTraitRef { bound_generic_params, trait_ref, span } = p; - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_trait_ref(trait_ref); vis.visit_span(span); } -pub fn noop_visit_struct_field(f: &mut StructField, visitor: &mut T) { - let StructField { span, ident, vis, id, ty, attrs } = f; +pub fn noop_flat_map_struct_field(mut sf: StructField, visitor: &mut T) + -> SmallVec<[StructField; 1]> +{ + let StructField { span, ident, vis, id, ty, attrs } = &mut sf; visitor.visit_span(span); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_vis(vis); visitor.visit_id(id); visitor.visit_ty(ty); visit_attrs(attrs, visitor); + smallvec![sf] } -pub fn noop_visit_field(f: &mut Field, vis: &mut T) { - let Field { ident, expr, span, is_shorthand: _, attrs, id } = f; +pub fn noop_flat_map_field(mut f: Field, vis: &mut T) -> SmallVec<[Field; 1]> { + let Field { ident, expr, span, is_shorthand: _, attrs, id } = &mut f; vis.visit_ident(ident); vis.visit_expr(expr); vis.visit_id(id); vis.visit_span(span); visit_thin_attrs(attrs, vis); + smallvec![f] } pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { @@ -858,7 +892,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_generics(generics); } ItemKind::Enum(EnumDef { variants }, generics) => { - visit_vec(variants, |variant| vis.visit_variant(variant)); + variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); vis.visit_generics(generics); } ItemKind::Struct(variant_data, generics) | @@ -1042,13 +1076,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { } PatKind::Struct(path, fields, _etc) => { vis.visit_path(path); - for FieldPat { ident, pat, is_shorthand: _, attrs, id, span } in fields { - vis.visit_ident(ident); - vis.visit_id(id); - vis.visit_pat(pat); - visit_thin_attrs(attrs, vis); - vis.visit_span(span); - }; + fields.flat_map_in_place(|field| vis.flat_map_field_pattern(field)); } PatKind::Box(inner) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), @@ -1130,7 +1158,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, } ExprKind::Match(expr, arms) => { vis.visit_expr(expr); - visit_vec(arms, |arm| vis.visit_arm(arm)); + arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); } ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => { vis.visit_asyncness(asyncness); @@ -1193,7 +1221,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, ExprKind::Mac(mac) => vis.visit_mac(mac), ExprKind::Struct(path, fields, expr) => { vis.visit_path(path); - visit_vec(fields, |field| vis.visit_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_field(field)); visit_opt(expr, |expr| vis.visit_expr(expr)); }, ExprKind::Paren(expr) => { diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index f17eb3b3943..a64fec70961 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -93,8 +93,7 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &VariantData, _: Ident, - _: &Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &VariantData) { self.count += 1; walk_struct_def(self, s) } @@ -107,9 +106,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &Variant) { self.count += 1; - walk_variant(self, v, g, item_id) + walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &Lifetime) { self.count += 1; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 91b92d84a81..86f6d36c3c6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -92,8 +92,7 @@ pub trait Visitor<'ast>: Sized { fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &'ast VariantData, _: Ident, - _: &'ast Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'ast VariantData) { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'ast StructField) { walk_struct_field(self, s) } @@ -101,8 +100,8 @@ pub trait Visitor<'ast>: Sized { generics: &'ast Generics, item_id: NodeId, _: Span) { walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) { - walk_variant(self, v, g, item_id) + fn visit_variant(&mut self, v: &'ast Variant) { + walk_variant(self, v) } fn visit_label(&mut self, label: &'ast Label) { walk_label(self, label) @@ -163,6 +162,12 @@ pub trait Visitor<'ast>: Sized { fn visit_fn_header(&mut self, _header: &'ast FnHeader) { // Nothing to do } + fn visit_field(&mut self, f: &'ast Field) { + walk_field(self, f) + } + fn visit_field_pattern(&mut self, fp: &'ast FieldPat) { + walk_field_pattern(self, fp) + } } #[macro_export] @@ -280,8 +285,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_variant_data(struct_definition, item.ident, - generics, item.id, item.span); + visitor.visit_variant_data(struct_definition); } ItemKind::Trait(.., ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); @@ -300,24 +304,32 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef, - generics: &'a Generics, - item_id: NodeId) { - walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); + _: &'a Generics, + _: NodeId) { + walk_list!(visitor, visit_variant, &enum_definition.variants); } -pub fn walk_variant<'a, V>(visitor: &mut V, - variant: &'a Variant, - generics: &'a Generics, - item_id: NodeId) +pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) where V: Visitor<'a>, { visitor.visit_ident(variant.ident); - visitor.visit_variant_data(&variant.data, variant.ident, - generics, item_id, variant.span); + visitor.visit_variant_data(&variant.data); walk_list!(visitor, visit_anon_const, &variant.disr_expr); walk_list!(visitor, visit_attribute, &variant.attrs); } +pub fn walk_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a Field) { + visitor.visit_expr(&f.expr); + visitor.visit_ident(f.ident); + walk_list!(visitor, visit_attribute, f.attrs.iter()); +} + +pub fn walk_field_pattern<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a FieldPat) { + visitor.visit_ident(fp.ident); + visitor.visit_pat(&fp.pat); + walk_list!(visitor, visit_attribute, fp.attrs.iter()); +} + pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { match typ.node { TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => { @@ -441,11 +453,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } PatKind::Struct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter()); - visitor.visit_ident(field.ident); - visitor.visit_pat(&field.pat) - } + walk_list!(visitor, visit_field_pattern, fields); } PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) | @@ -686,11 +694,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { } ExprKind::Struct(ref path, ref fields, ref optional_base) => { visitor.visit_path(path, expression.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter()); - visitor.visit_ident(field.ident); - visitor.visit_expr(&field.expr) - } + walk_list!(visitor, visit_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(ref subexpressions) => { From 365ff62fca0e1fb6511a47f5f50c4af4df250dfa Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 24 Aug 2019 18:25:34 +0100 Subject: [PATCH 7/8] Don't unwrap the result of `span_to_snippet` It can return `Err` due to macros being expanded across crates or files. --- src/librustc_mir/borrow_check/move_errors.rs | 84 ++++++++++--------- .../borrow_check/mutability_errors.rs | 4 +- .../ui/borrowck/move-error-snippets-ext.rs | 7 ++ src/test/ui/borrowck/move-error-snippets.rs | 23 +++++ .../ui/borrowck/move-error-snippets.stderr | 15 ++++ 5 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/borrowck/move-error-snippets-ext.rs create mode 100644 src/test/ui/borrowck/move-error-snippets.rs create mode 100644 src/test/ui/borrowck/move-error-snippets.stderr diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 738a091b0dd..f10ff71b15e 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -415,20 +415,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "{:?}", move_place.ty(self.body, self.infcx.tcx).ty, ); - let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); - let is_option = move_ty.starts_with("std::option::Option"); - let is_result = move_ty.starts_with("std::result::Result"); - if is_option || is_result { - err.span_suggestion( - span, - &format!("consider borrowing the `{}`'s content", if is_option { - "Option" - } else { - "Result" - }), - format!("{}.as_ref()", snippet), - Applicability::MaybeIncorrect, - ); + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + let is_option = move_ty.starts_with("std::option::Option"); + let is_result = move_ty.starts_with("std::result::Result"); + if is_option || is_result { + err.span_suggestion( + span, + &format!("consider borrowing the `{}`'s content", if is_option { + "Option" + } else { + "Result" + }), + format!("{}.as_ref()", snippet), + Applicability::MaybeIncorrect, + ); + } } err } @@ -439,19 +440,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'a>, span: Span, ) { - let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::Unspecified, - ); + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::Unspecified, + ); + } if binds_to.is_empty() { let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; @@ -517,27 +519,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. })) ) = bind_to.is_user_variable { - let pat_snippet = self.infcx.tcx.sess.source_map() - .span_to_snippet(pat_span) - .unwrap(); - if pat_snippet.starts_with('&') { - let pat_snippet = pat_snippet[1..].trim_start(); - let suggestion; - let to_remove; - if pat_snippet.starts_with("mut") - && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) - { - suggestion = pat_snippet["mut".len()..].trim_start(); - to_remove = "&mut"; - } else { - suggestion = pat_snippet; - to_remove = "&"; + if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) + { + if pat_snippet.starts_with('&') { + let pat_snippet = pat_snippet[1..].trim_start(); + let suggestion; + let to_remove; + if pat_snippet.starts_with("mut") + && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) + { + suggestion = pat_snippet["mut".len()..].trim_start(); + to_remove = "&mut"; + } else { + suggestion = pat_snippet; + to_remove = "&"; + } + suggestions.push(( + pat_span, + to_remove, + suggestion.to_owned(), + )); } - suggestions.push(( - pat_span, - to_remove, - suggestion.to_owned(), - )); } } } diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 937c6383be3..e7f37431e50 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -711,8 +711,8 @@ fn annotate_struct_field( } /// If possible, suggest replacing `ref` with `ref mut`. -fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option<(String)> { - let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).unwrap(); +fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option { + let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?; if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(Pattern_White_Space) { diff --git a/src/test/ui/borrowck/move-error-snippets-ext.rs b/src/test/ui/borrowck/move-error-snippets-ext.rs new file mode 100644 index 00000000000..c77f6c8276e --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets-ext.rs @@ -0,0 +1,7 @@ +// ignore-test + +macro_rules! aaa { + ($c:ident) => {{ + let a = $c; + }} +} diff --git a/src/test/ui/borrowck/move-error-snippets.rs b/src/test/ui/borrowck/move-error-snippets.rs new file mode 100644 index 00000000000..64f95653828 --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets.rs @@ -0,0 +1,23 @@ +// Test that we don't ICE after trying to construct a cross-file snippet #63800. + +// compile-flags: --test + +#[macro_use] +#[path = "move-error-snippets-ext.rs"] +mod move_error_snippets_ext; + +struct A; + +macro_rules! sss { + () => { + #[test] + fn fff() { + static D: A = A; + aaa!(D); //~ ERROR cannot move + } + }; +} + +sss!(); + +fn main() {} diff --git a/src/test/ui/borrowck/move-error-snippets.stderr b/src/test/ui/borrowck/move-error-snippets.stderr new file mode 100644 index 00000000000..77463c48591 --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of static item `D` + --> $DIR/move-error-snippets.rs:16:18 + | +LL | | #[macro_use] + | |__________________^ move occurs because `D` has type `A`, which does not implement the `Copy` trait +... +LL | aaa!(D); + | __________________^ +... +LL | sss!(); + | ------- in this macro invocation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. From 3890befa8ea9def7e1c9c57a321c7b8c9f759f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 24 Aug 2019 14:54:35 -0700 Subject: [PATCH 8/8] review comment --- src/librustc/ty/sty.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7b7e2b8bfbd..f41fffe507d 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -385,7 +385,6 @@ impl<'tcx> ClosureSubsts<'tcx> { let ty = self.closure_sig_ty(def_id, tcx); match ty.sty { ty::FnPtr(sig) => sig, - ty::Infer(_) | ty::Error => ty::Binder::dummy(FnSig::fake()), // ignore errors _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty.sty), } }