From f2d7c05db0e4876b9c409a8be8e99aceadc34b1a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 20 Dec 2020 21:07:13 -0500 Subject: [PATCH 01/23] Don't try to add nested predicate to Rustdoc auto-trait `ParamEnv` Fixes #80233 We already have logic in `evaluate_predicates` that tries to add unimplemented predicates to our `ParamEnv`. Trying to add a predicate that already holds can lead to errors later on, since projection will prefer trait candidates from the `ParamEnv` to predicates from an impl. --- .../src/traits/auto_trait.rs | 10 ++--- .../issue-80233-normalize-auto-trait.rs | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc/issue-80233-normalize-auto-trait.rs diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6ab16886ed237..d0486264a58f9 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -642,12 +642,10 @@ impl AutoTraitFinder<'tcx> { let bound_predicate = predicate.bound_atom(); match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(p, _) => { - if self.is_param_no_infer(p.trait_ref.substs) - && !only_projections - && is_new_pred - { - self.add_user_pred(computed_preds, predicate); - } + // Add this to `predicates` so that we end up calling `select` + // with it. If this predicate ends up being unimplemented, + // then `evaluate_predicates` will handle adding it the `ParamEnv` + // if possible. predicates.push_back(bound_predicate.rebind(p)); } ty::PredicateAtom::Projection(p) => { diff --git a/src/test/rustdoc/issue-80233-normalize-auto-trait.rs b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs new file mode 100644 index 0000000000000..585a0864bb25d --- /dev/null +++ b/src/test/rustdoc/issue-80233-normalize-auto-trait.rs @@ -0,0 +1,37 @@ +// Regression test for issue #80233 +// Tests that we don't ICE when processing auto traits + +#![crate_type = "lib"] +pub trait Trait1 {} + +pub trait Trait2 { + type Type2; +} + +pub trait Trait3 { + type Type3; +} + +impl Trait2 for Struct1 { + type Type2 = Struct1; +} + +impl Trait2 for Vec { + type Type2 = Vec; +} + +impl Trait3 for T { + type Type3 = Struct1; +} + +impl Trait3 for Vec { + type Type3 = Vec; +} + +pub struct Struct1 {} + +// @has issue_80233_normalize_auto_trait/struct.Question.html +// @has - '//code' 'impl Send for Question' +pub struct Question { + pub ins: < as Trait3>::Type3 as Trait2>::Type2, +} From 988e2f9b2f654442ec1157e431e4c26d311e0446 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 5 Jan 2021 10:07:50 +0100 Subject: [PATCH 02/23] First version of noop-lint --- compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/noop_method_call.rs | 71 +++++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/clone.rs | 2 + 4 files changed, 77 insertions(+) create mode 100644 compiler/rustc_lint/src/noop_method_call.rs diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 2336b52619ab8..3fff2303ac681 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -55,6 +55,7 @@ mod levels; mod methods; mod non_ascii_idents; mod nonstandard_style; +mod noop_method_call; mod panic_fmt; mod passes; mod redundant_semicolon; @@ -81,6 +82,7 @@ use internal::*; use methods::*; use non_ascii_idents::*; use nonstandard_style::*; +use noop_method_call::*; use panic_fmt::PanicFmt; use redundant_semicolon::*; use traits::*; @@ -168,6 +170,7 @@ macro_rules! late_lint_passes { ClashingExternDeclarations: ClashingExternDeclarations::new(), DropTraitConstraints: DropTraitConstraints, TemporaryCStringAsPtr: TemporaryCStringAsPtr, + NoopMethodCall: NoopMethodCall, PanicFmt: PanicFmt, ] ); diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs new file mode 100644 index 0000000000000..098c50d5abe19 --- /dev/null +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -0,0 +1,71 @@ +use crate::context::LintContext; +use crate::rustc_middle::ty::TypeFoldable; +use crate::LateContext; +use crate::LateLintPass; +use rustc_hir::def::DefKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +declare_lint! { + /// The `noop_method_call` lint detects specific calls to noop methods + /// such as a calling `<&T as Clone>::clone` where `T: !Clone`. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// struct Foo; + /// let foo = &Foo; + /// let clone: &Foo = foo.clone(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Some method calls are noops meaning that they do nothing. Usually such methods + /// are the result of blanket implementations that happen to create some method invocations + /// that end up not doing anything. For instance, `Clone` is implemented on all `&T`, but + /// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything + /// as references are copy. This lint detects these calls and warns the user about them. + pub NOOP_METHOD_CALL, + Warn, + "detects the use of well-known noop methods" +} + +declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); + +impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + // We only care about method calls + if let ExprKind::MethodCall(..) = expr.kind { + // Get the `DefId` only when dealing with an `AssocFn` + if let Some((DefKind::AssocFn, did)) = + cx.typeck_results().type_dependent_def(expr.hir_id) + { + // Check that we're dealing with a trait method + if let Some(trait_id) = cx.tcx.trait_of_item(did) { + let substs = cx.typeck_results().node_substs(expr.hir_id); + // We can't resolve on types that recursively require monomorphization, + // so check that we don't need to perfom substitution + if !substs.needs_subst() { + let param_env = cx.tcx.param_env(trait_id); + // Resolve the trait method instance + if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { + // Check that it implements the noop diagnostic + if cx.tcx.is_diagnostic_item(sym::ref_clone_method, i.def_id()) { + let span = expr.span; + + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + let message = "Call to noop method"; + lint.build(&message).emit() + }); + } + } + } + } + } + } + } +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b6cf584d875f1..0f7b4d2efc775 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -887,6 +887,7 @@ symbols! { receiver, recursion_limit, reexport_test_harness_main, + ref_clone_method, reference, reflect, reg, diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index a953a3a4182bc..12f0f9629a31f 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -104,6 +104,7 @@ /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] +#[rustc_diagnostic_item = "Clone"] pub trait Clone: Sized { /// Returns a copy of the value. /// @@ -221,6 +222,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for &T { #[inline] + #[rustc_diagnostic_item = "ref_clone_method"] fn clone(&self) -> Self { *self } From 58e3a4a24a4e5345ac0b095ecdb80bd9b476fb0c Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 5 Jan 2021 16:14:39 +0100 Subject: [PATCH 03/23] Add tests and support two more noop methods --- compiler/rustc_lint/src/noop_method_call.rs | 12 +++++- compiler/rustc_span/src/symbol.rs | 4 +- library/core/src/borrow.rs | 1 + library/core/src/clone.rs | 3 +- library/core/src/ops/deref.rs | 1 + src/test/ui/lint/noop-method-call.rs | 45 +++++++++++++++++++++ src/test/ui/lint/noop-method-call.stderr | 28 +++++++++++++ 7 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/lint/noop-method-call.rs create mode 100644 src/test/ui/lint/noop-method-call.stderr diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 098c50d5abe19..3ab3fab4272c7 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -54,11 +54,19 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // Resolve the trait method instance if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { // Check that it implements the noop diagnostic - if cx.tcx.is_diagnostic_item(sym::ref_clone_method, i.def_id()) { + tracing::debug!("Resolves to: {:?}", i.def_id()); + if [ + sym::noop_method_borrow, + sym::noop_method_clone, + sym::noop_method_deref, + ] + .iter() + .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) + { let span = expr.span; cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let message = "Call to noop method"; + let message = "call to noop method"; lint.build(&message).emit() }); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0f7b4d2efc775..4ca5a8f392c15 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -765,6 +765,9 @@ symbols! { none_error, nontemporal_store, nontrapping_dash_fptoint: "nontrapping-fptoint", + noop_method_borrow, + noop_method_clone, + noop_method_deref, noreturn, nostack, not, @@ -887,7 +890,6 @@ symbols! { receiver, recursion_limit, reexport_test_harness_main, - ref_clone_method, reference, reflect, reg, diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index c9040cd0a1670..af2ad12dddf0a 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -219,6 +219,7 @@ impl BorrowMut for T { #[stable(feature = "rust1", since = "1.0.0")] impl Borrow for &T { + #[rustc_diagnostic_item = "noop_method_borrow"] fn borrow(&self) -> &T { &**self } diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 12f0f9629a31f..12b4feeb14ae3 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -104,7 +104,6 @@ /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] -#[rustc_diagnostic_item = "Clone"] pub trait Clone: Sized { /// Returns a copy of the value. /// @@ -222,7 +221,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for &T { #[inline] - #[rustc_diagnostic_item = "ref_clone_method"] + #[rustc_diagnostic_item = "noop_method_clone"] fn clone(&self) -> Self { *self } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 245152e5490d8..9c3d66696c890 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -77,6 +77,7 @@ pub trait Deref { impl Deref for &T { type Target = T; + #[rustc_diagnostic_item = "noop_method_deref"] fn deref(&self) -> &T { *self } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs new file mode 100644 index 0000000000000..4b81e04d3f7f9 --- /dev/null +++ b/src/test/ui/lint/noop-method-call.rs @@ -0,0 +1,45 @@ +// check-pass + +#![allow(unused)] + +use std::borrow::Borrow; +use std::ops::Deref; + +struct Foo(T); + +#[derive(Clone)] +struct Bar(T); + +struct DerefExample(T); + +impl Deref for DerefExample { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let foo = &Foo(1u32); + let foo_clone: &Foo = foo.clone(); //~ WARNING call to noop method + + let bar = &Bar(1u32); + let bar_clone: Bar = bar.clone(); + + let deref = &&DerefExample(12u32); + let derefed: &DerefExample = deref.deref(); //~ WARNING call to noop method + + let deref = &DerefExample(12u32); + let derefed: &u32 = deref.deref(); + + let a = &&Foo(1u32); + let borrowed: &Foo = a.borrow(); //~ WARNING call to noop method +} + +fn generic(foo: &Foo) { + foo.clone(); +} + +fn non_generic(foo: &Foo) { + foo.clone(); //~ WARNING call to noop method +} diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr new file mode 100644 index 0000000000000..1120adee121b1 --- /dev/null +++ b/src/test/ui/lint/noop-method-call.stderr @@ -0,0 +1,28 @@ +warning: call to noop method + --> $DIR/noop-method-call.rs:24:32 + | +LL | let foo_clone: &Foo = foo.clone(); + | ^^^^^^^^^^^ + | + = note: `#[warn(noop_method_call)]` on by default + +warning: call to noop method + --> $DIR/noop-method-call.rs:30:39 + | +LL | let derefed: &DerefExample = deref.deref(); + | ^^^^^^^^^^^^^ + +warning: call to noop method + --> $DIR/noop-method-call.rs:36:31 + | +LL | let borrowed: &Foo = a.borrow(); + | ^^^^^^^^^^ + +warning: call to noop method + --> $DIR/noop-method-call.rs:44:5 + | +LL | foo.clone(); + | ^^^^^^^^^^^ + +warning: 4 warnings emitted + From e29cefdfd4c8f34428641626014fad883c458f1b Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 5 Jan 2021 16:46:50 +0100 Subject: [PATCH 04/23] Fix tests --- compiler/rustc_codegen_ssa/src/back/rpath.rs | 2 +- compiler/rustc_lint/src/noop_method_call.rs | 9 ++++++++- compiler/rustc_middle/src/ty/error.rs | 2 -- compiler/rustc_mir/src/borrow_check/invalidation.rs | 8 ++++---- compiler/rustc_mir_build/src/build/matches/test.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 ++ .../src/traits/error_reporting/mod.rs | 2 +- compiler/rustc_traits/src/chalk/mod.rs | 4 ++-- compiler/rustc_typeck/src/check/callee.rs | 2 +- compiler/rustc_typeck/src/check/expr.rs | 2 +- library/core/src/borrow.rs | 1 + library/core/src/clone.rs | 1 + library/core/src/ops/deref.rs | 1 + src/test/ui/issues/issue-11820.rs | 10 ++++++---- src/test/ui/underscore-imports/cycle.rs | 1 + src/test/ui/underscore-imports/hygiene-2.rs | 1 + src/test/ui/underscore-imports/macro-expanded.rs | 1 + 17 files changed, 33 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 005d2efdd3b26..5f21046b05e47 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -24,7 +24,7 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec { debug!("preparing the RPATH!"); - let libs = config.used_crates.clone(); + let libs = config.used_crates; let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::>(); let rpaths = get_rpaths(config, &libs); let mut flags = rpaths_to_flags(&rpaths); diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 3ab3fab4272c7..dad557128f8b7 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -46,6 +46,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { { // Check that we're dealing with a trait method if let Some(trait_id) = cx.tcx.trait_of_item(did) { + // Check we're dealing with one of the traits we care about + if ![sym::Clone, sym::Deref, sym::Borrow] + .iter() + .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) + { + return; + } + let substs = cx.typeck_results().node_substs(expr.hir_id); // We can't resolve on types that recursively require monomorphization, // so check that we don't need to perfom substitution @@ -54,7 +62,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // Resolve the trait method instance if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { // Check that it implements the noop diagnostic - tracing::debug!("Resolves to: {:?}", i.def_id()); if [ sym::noop_method_borrow, sym::noop_method_clone, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index fe20925b38798..b6a3a15cfbebe 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -12,7 +12,6 @@ use rustc_target::spec::abi; use std::borrow::Cow; use std::fmt; -use std::ops::Deref; #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] pub struct ExpectedFound { @@ -535,7 +534,6 @@ impl Trait for X { TargetFeatureCast(def_id) => { let attrs = self.get_attrs(*def_id); let target_spans = attrs - .deref() .iter() .filter(|attr| attr.has_name(sym::target_feature)) .map(|attr| attr.span); diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs index 8c05e6fd5d0e4..e423e449746fc 100644 --- a/compiler/rustc_mir/src/borrow_check/invalidation.rs +++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs @@ -165,7 +165,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.consume_operand(location, value); // Invalidate all borrows of local places - let borrow_set = self.borrow_set.clone(); + let borrow_set = self.borrow_set; let resume = self.location_table.start_index(resume.start_location()); for (i, data) in borrow_set.iter_enumerated() { if borrow_of_local_data(data.borrowed_place) { @@ -177,7 +177,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { // Invalidate all borrows of local places - let borrow_set = self.borrow_set.clone(); + let borrow_set = self.borrow_set; let start = self.location_table.start_index(location); for (i, data) in borrow_set.iter_enumerated() { if borrow_of_local_data(data.borrowed_place) { @@ -369,7 +369,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { ); let tcx = self.tcx; let body = self.body; - let borrow_set = self.borrow_set.clone(); + let borrow_set = self.borrow_set; let indices = self.borrow_set.indices(); each_borrow_involving_path( self, @@ -377,7 +377,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { body, location, (sd, place), - &borrow_set.clone(), + borrow_set, indices, |this, borrow_index, borrow| { match (rw, borrow.kind) { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 07173f41cd6db..a81f93729381d 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Constant { value } => Test { span: match_pair.pattern.span, - kind: TestKind::Eq { value, ty: match_pair.pattern.ty.clone() }, + kind: TestKind::Eq { value, ty: match_pair.pattern.ty }, }, PatKind::Range(range) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4ca5a8f392c15..7c2626a31e269 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -126,6 +126,7 @@ symbols! { Argument, ArgumentV1, Arguments, + Borrow, C, CString, Center, @@ -136,6 +137,7 @@ symbols! { Decodable, Decoder, Default, + Deref, Encodable, Encoder, Eq, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index a439bb892f8e7..d83641afe72ca 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -828,7 +828,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { sig.decl .inputs .iter() - .map(|arg| match arg.clone().kind { + .map(|arg| match arg.kind { hir::TyKind::Tup(ref tys) => ArgKind::Tuple( Some(arg.span), vec![("_".to_owned(), "_".to_owned()); tys.len()], diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index bd2f87f70a2f1..23a2baf2496f6 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -112,7 +112,7 @@ crate fn evaluate_goal<'tcx>( }); let sol = Canonical { max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables.clone(), + variables: obligation.variables, value: QueryResponse { var_values: CanonicalVarValues { var_values }, region_constraints: QueryRegionConstraints::default(), @@ -137,7 +137,7 @@ crate fn evaluate_goal<'tcx>( // let's just ignore that let sol = Canonical { max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables.clone(), + variables: obligation.variables, value: QueryResponse { var_values: CanonicalVarValues { var_values: IndexVec::new() } .make_identity(tcx), diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 116b079e7425a..b30fa71aa755b 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -446,7 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected_arg_tys = self.expected_inputs_for_expected_output( call_expr.span, expected, - fn_sig.output().clone(), + fn_sig.output(), fn_sig.inputs(), ); diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index d76a80d5a3990..15004138afb1e 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -710,7 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let ret_ty = ret_coercion.borrow().expected_ty(); - let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone()); + let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); ret_coercion.borrow_mut().coerce( self, &self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)), diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index af2ad12dddf0a..a0cdf681f67e1 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -153,6 +153,7 @@ /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`String`]: ../../std/string/struct.String.html #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Borrow"] pub trait Borrow { /// Immutably borrows from an owned value. /// diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 12b4feeb14ae3..957769cdc5a62 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -104,6 +104,7 @@ /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] +#[rustc_diagnostic_item = "Clone"] pub trait Clone: Sized { /// Returns a copy of the value. /// diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 9c3d66696c890..8911772604aaf 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -60,6 +60,7 @@ #[doc(alias = "*")] #[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Deref"] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/issues/issue-11820.rs b/src/test/ui/issues/issue-11820.rs index 7ffe9652797cf..8a26624a05dc9 100644 --- a/src/test/ui/issues/issue-11820.rs +++ b/src/test/ui/issues/issue-11820.rs @@ -1,12 +1,14 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(noop_method_call)] + struct NoClone; fn main() { - let rnc = &NoClone; - let rsnc = &Some(NoClone); + let rnc = &NoClone; + let rsnc = &Some(NoClone); - let _: &NoClone = rnc.clone(); - let _: &Option = rsnc.clone(); + let _: &NoClone = rnc.clone(); + let _: &Option = rsnc.clone(); } diff --git a/src/test/ui/underscore-imports/cycle.rs b/src/test/ui/underscore-imports/cycle.rs index bacf9b2d5a96a..987410fa84b20 100644 --- a/src/test/ui/underscore-imports/cycle.rs +++ b/src/test/ui/underscore-imports/cycle.rs @@ -14,5 +14,6 @@ mod y { pub fn main() { use x::*; + #[allow(noop_method_call)] (&0).deref(); } diff --git a/src/test/ui/underscore-imports/hygiene-2.rs b/src/test/ui/underscore-imports/hygiene-2.rs index bea61eae6b51a..510d91d0d4624 100644 --- a/src/test/ui/underscore-imports/hygiene-2.rs +++ b/src/test/ui/underscore-imports/hygiene-2.rs @@ -29,5 +29,6 @@ m!(y); fn main() { use crate::y::*; + #[allow(noop_method_call)] (&()).deref(); } diff --git a/src/test/ui/underscore-imports/macro-expanded.rs b/src/test/ui/underscore-imports/macro-expanded.rs index 43f527bc9a408..55e86e848558d 100644 --- a/src/test/ui/underscore-imports/macro-expanded.rs +++ b/src/test/ui/underscore-imports/macro-expanded.rs @@ -3,6 +3,7 @@ // check-pass #![feature(decl_macro, rustc_attrs)] +#![allow(noop_method_call)] mod x { pub use std::ops::Not as _; From 9777e0c0e45ff20f6ef55e03d091276b10af0d99 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 6 Jan 2021 14:48:06 +0100 Subject: [PATCH 05/23] Bless test where order of error message changed --- src/test/ui/panic-handler/weak-lang-item.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr index 68e3e21df3e08..b7c040c7a850b 100644 --- a/src/test/ui/panic-handler/weak-lang-item.stderr +++ b/src/test/ui/panic-handler/weak-lang-item.stderr @@ -10,10 +10,10 @@ help: you can use `as` to change the binding name of the import LL | extern crate core as other_core; | -error: language item required, but not found: `eh_personality` - error: `#[panic_handler]` function required, but not found +error: language item required, but not found: `eh_personality` + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0259`. From f3bbb980a9765d32a891438157cc455b64d4d650 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 6 Jan 2021 17:56:34 +0100 Subject: [PATCH 06/23] Fix ui-full-deps suite --- library/alloc/src/collections/btree/map/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index f92aed8ce15bf..5a4eae165a50d 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1633,11 +1633,11 @@ fn test_occupied_entry_key() { let key = "hello there"; let value = "value goes here"; assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); + a.insert(key, value); assert_eq!(a.len(), 1); assert_eq!(a[key], value); - match a.entry(key.clone()) { + match a.entry(key) { Vacant(_) => panic!(), Occupied(e) => assert_eq!(key, *e.key()), } @@ -1653,11 +1653,11 @@ fn test_vacant_entry_key() { let value = "value goes here"; assert!(a.is_empty()); - match a.entry(key.clone()) { + match a.entry(key) { Occupied(_) => panic!(), Vacant(e) => { assert_eq!(key, *e.key()); - e.insert(value.clone()); + e.insert(value); } } assert_eq!(a.len(), 1); From ac50400aade9f835875bc38d4d017b7036f6cde9 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 6 Jan 2021 21:11:08 +0100 Subject: [PATCH 07/23] Fix core tests --- library/core/src/clone.rs | 1 + library/core/tests/clone.rs | 2 ++ library/core/tests/iter.rs | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 957769cdc5a62..51a2dc03de318 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -111,6 +111,7 @@ pub trait Clone: Sized { /// # Examples /// /// ``` + /// # #![allow(noop_method_call)] /// let hello = "Hello"; // &str implements Clone /// /// assert_eq!("Hello", hello.clone()); diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index c97a87aebce41..e5787d79c3226 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,3 +1,5 @@ +#![allow(noop_method_call)] + #[test] fn test_borrowed_clone() { let x = 5; diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 7376e7848eff5..3dff2ebf8f0e9 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -3509,7 +3509,7 @@ pub fn extend_for_unit() { #[test] fn test_intersperse() { let xs = ["a", "", "b", "c"]; - let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); + let v: Vec<&str> = xs.iter().map(|x| *x).intersperse(", ").collect(); let text: String = v.concat(); assert_eq!(text, "a, , b, c".to_string()); @@ -3521,7 +3521,7 @@ fn test_intersperse() { #[test] fn test_intersperse_size_hint() { let xs = ["a", "", "b", "c"]; - let mut iter = xs.iter().map(|x| x.clone()).intersperse(", "); + let mut iter = xs.iter().map(|x| *x).intersperse(", "); assert_eq!(iter.size_hint(), (7, Some(7))); assert_eq!(iter.next(), Some("a")); From 8ac6481ef8beab758018c97c47bfaa4abffd297e Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 7 Jan 2021 11:24:32 +0100 Subject: [PATCH 08/23] Only allow new lint when not bootstrapping - since beta doesn't know about the lint --- library/core/tests/clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index e5787d79c3226..2f2aa9a20f912 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,4 +1,4 @@ -#![allow(noop_method_call)] +#![cfg_attr(not(bootstrap), allow(noop_method_call))] #[test] fn test_borrowed_clone() { From cdcb3b5160f3d6b44f77e5b077ca22c22a7b62c9 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 7 Jan 2021 13:13:25 +0100 Subject: [PATCH 09/23] Fix std tests --- library/std/src/collections/hash/map/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 467968354e25d..819be14222752 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -774,11 +774,11 @@ fn test_occupied_entry_key() { let key = "hello there"; let value = "value goes here"; assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); + a.insert(key, value); assert_eq!(a.len(), 1); assert_eq!(a[key], value); - match a.entry(key.clone()) { + match a.entry(key) { Vacant(_) => panic!(), Occupied(e) => assert_eq!(key, *e.key()), } @@ -793,11 +793,11 @@ fn test_vacant_entry_key() { let value = "value goes here"; assert!(a.is_empty()); - match a.entry(key.clone()) { + match a.entry(key) { Occupied(_) => panic!(), Vacant(e) => { assert_eq!(key, *e.key()); - e.insert(value.clone()); + e.insert(value); } } assert_eq!(a.len(), 1); From fd81c874f0e7e28a96429416dbfdcdbf2d0e396c Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 8 Jan 2021 11:37:52 +0100 Subject: [PATCH 10/23] Improve warning --- compiler/rustc_lint/src/noop_method_call.rs | 10 ++++++---- src/test/ui/lint/noop-method-call.rs | 8 ++++---- src/test/ui/lint/noop-method-call.stderr | 16 ++++++++-------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index dad557128f8b7..b9b5009d9dd95 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -70,11 +70,13 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { .iter() .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) { - let span = expr.span; + let expr_span = expr.span; - cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let message = "call to noop method"; - lint.build(&message).emit() + cx.struct_span_lint(NOOP_METHOD_CALL, expr_span, |lint| { + let message = "call to method that does nothing"; + lint.build(&message) + .span_label(expr_span, "unnecessary method call") + .emit() }); } } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index 4b81e04d3f7f9..b8ff75845bd7d 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -21,19 +21,19 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); - let foo_clone: &Foo = foo.clone(); //~ WARNING call to noop method + let foo_clone: &Foo = foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); - let derefed: &DerefExample = deref.deref(); //~ WARNING call to noop method + let derefed: &DerefExample = deref.deref(); //~ WARNING call to method that does nothing [noop_method_call] let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); - let borrowed: &Foo = a.borrow(); //~ WARNING call to noop method + let borrowed: &Foo = a.borrow(); //~ WARNING call to method that does nothing [noop_method_call] } fn generic(foo: &Foo) { @@ -41,5 +41,5 @@ fn generic(foo: &Foo) { } fn non_generic(foo: &Foo) { - foo.clone(); //~ WARNING call to noop method + foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 1120adee121b1..f5b766f42333f 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,28 +1,28 @@ -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:24:32 | LL | let foo_clone: &Foo = foo.clone(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:30:39 | LL | let derefed: &DerefExample = deref.deref(); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ unnecessary method call -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:36:31 | LL | let borrowed: &Foo = a.borrow(); - | ^^^^^^^^^^ + | ^^^^^^^^^^ unnecessary method call -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:44:5 | LL | foo.clone(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ unnecessary method call warning: 4 warnings emitted From a35655621a7a7c0d41093e177855f46bce75fa30 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 8 Jan 2021 12:09:29 +0100 Subject: [PATCH 11/23] Fix tidy errors --- src/test/ui/lint/noop-method-call.rs | 9 ++++++--- src/test/ui/lint/noop-method-call.stderr | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index b8ff75845bd7d..9f0ab3960f8dd 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -21,19 +21,22 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); - let foo_clone: &Foo = foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] + let foo_clone: &Foo = foo.clone(); + //~^ WARNING call to method that does nothing [noop_method_call] let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); - let derefed: &DerefExample = deref.deref(); //~ WARNING call to method that does nothing [noop_method_call] + let derefed: &DerefExample = deref.deref(); + //~^ WARNING call to method that does nothing [noop_method_call] let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); - let borrowed: &Foo = a.borrow(); //~ WARNING call to method that does nothing [noop_method_call] + let borrowed: &Foo = a.borrow(); + //~^ WARNING call to method that does nothing [noop_method_call] } fn generic(foo: &Foo) { diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index f5b766f42333f..32acf1632336d 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -7,19 +7,19 @@ LL | let foo_clone: &Foo = foo.clone(); = note: `#[warn(noop_method_call)]` on by default warning: call to method that does nothing - --> $DIR/noop-method-call.rs:30:39 + --> $DIR/noop-method-call.rs:31:39 | LL | let derefed: &DerefExample = deref.deref(); | ^^^^^^^^^^^^^ unnecessary method call warning: call to method that does nothing - --> $DIR/noop-method-call.rs:36:31 + --> $DIR/noop-method-call.rs:38:31 | LL | let borrowed: &Foo = a.borrow(); | ^^^^^^^^^^ unnecessary method call warning: call to method that does nothing - --> $DIR/noop-method-call.rs:44:5 + --> $DIR/noop-method-call.rs:47:5 | LL | foo.clone(); | ^^^^^^^^^^^ unnecessary method call From 8ded7852edcdabfe630fe18fdc5e8e3cbcae0e28 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Mon, 11 Jan 2021 11:47:16 +0100 Subject: [PATCH 12/23] Update error message --- compiler/rustc_lint/src/noop_method_call.rs | 9 ++++++--- src/test/ui/issues/issue-11820.rs | 8 ++++---- src/test/ui/lint/noop-method-call.rs | 9 +++++---- src/test/ui/lint/noop-method-call.stderr | 19 +++++++++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index b9b5009d9dd95..e91dd37d8aaae 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -39,7 +39,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // We only care about method calls - if let ExprKind::MethodCall(..) = expr.kind { + if let ExprKind::MethodCall(call, ..) = expr.kind { // Get the `DefId` only when dealing with an `AssocFn` if let Some((DefKind::AssocFn, did)) = cx.typeck_results().type_dependent_def(expr.hir_id) @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { } let substs = cx.typeck_results().node_substs(expr.hir_id); - // We can't resolve on types that recursively require monomorphization, + // We can't resolve on types that require monomorphization, // so check that we don't need to perfom substitution if !substs.needs_subst() { let param_env = cx.tcx.param_env(trait_id); @@ -73,9 +73,12 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { let expr_span = expr.span; cx.struct_span_lint(NOOP_METHOD_CALL, expr_span, |lint| { - let message = "call to method that does nothing"; + let method = &call.ident.name; + let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); lint.build(&message) .span_label(expr_span, "unnecessary method call") + .note("the type the method is being called on and the return type are functionally equivalent.") + .note("therefore, the method call doesn't actually do anything and can be removed.") .emit() }); } diff --git a/src/test/ui/issues/issue-11820.rs b/src/test/ui/issues/issue-11820.rs index 8a26624a05dc9..dc6349b10ee58 100644 --- a/src/test/ui/issues/issue-11820.rs +++ b/src/test/ui/issues/issue-11820.rs @@ -6,9 +6,9 @@ struct NoClone; fn main() { - let rnc = &NoClone; - let rsnc = &Some(NoClone); + let rnc = &NoClone; + let rsnc = &Some(NoClone); - let _: &NoClone = rnc.clone(); - let _: &Option = rsnc.clone(); + let _: &NoClone = rnc.clone(); + let _: &Option = rsnc.clone(); } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index 9f0ab3960f8dd..b8aa55e1e1da6 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -22,21 +22,21 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); let foo_clone: &Foo = foo.clone(); - //~^ WARNING call to method that does nothing [noop_method_call] + //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); let derefed: &DerefExample = deref.deref(); - //~^ WARNING call to method that does nothing [noop_method_call] + //~^ WARNING call to `.deref()` on a reference in this situation does nothing [noop_method_call] let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); let borrowed: &Foo = a.borrow(); - //~^ WARNING call to method that does nothing [noop_method_call] + //~^ WARNING call to `.borrow()` on a reference in this situation does nothing [noop_method_call] } fn generic(foo: &Foo) { @@ -44,5 +44,6 @@ fn generic(foo: &Foo) { } fn non_generic(foo: &Foo) { - foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] + foo.clone(); + //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 32acf1632336d..f9cc9735d54f6 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,28 +1,39 @@ -warning: call to method that does nothing +warning: call to `.clone()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:24:32 | LL | let foo_clone: &Foo = foo.clone(); | ^^^^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. -warning: call to method that does nothing +warning: call to `.deref()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:31:39 | LL | let derefed: &DerefExample = deref.deref(); | ^^^^^^^^^^^^^ unnecessary method call + | + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. -warning: call to method that does nothing +warning: call to `.borrow()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:38:31 | LL | let borrowed: &Foo = a.borrow(); | ^^^^^^^^^^ unnecessary method call + | + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. -warning: call to method that does nothing +warning: call to `.clone()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:47:5 | LL | foo.clone(); | ^^^^^^^^^^^ unnecessary method call + | + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. warning: 4 warnings emitted From 7cf66b8214b8aaca9dea5722f7991d008ec8a301 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Mon, 11 Jan 2021 19:02:19 +0100 Subject: [PATCH 13/23] Fix tidy error --- src/test/ui/lint/noop-method-call.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index b8aa55e1e1da6..bc61d619abe82 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -22,21 +22,21 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); let foo_clone: &Foo = foo.clone(); - //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.clone()` on a reference in this situation does nothing let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); let derefed: &DerefExample = deref.deref(); - //~^ WARNING call to `.deref()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.deref()` on a reference in this situation does nothing let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); let borrowed: &Foo = a.borrow(); - //~^ WARNING call to `.borrow()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.borrow()` on a reference in this situation does nothing } fn generic(foo: &Foo) { @@ -45,5 +45,5 @@ fn generic(foo: &Foo) { fn non_generic(foo: &Foo) { foo.clone(); - //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.clone()` on a reference in this situation does nothing } From 7b7708e663969859e1b549cf1191037450391457 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 12 Jan 2021 14:58:51 +0100 Subject: [PATCH 14/23] Improve error messages --- compiler/rustc_lint/src/noop_method_call.rs | 18 +++++++++---- src/test/ui/lint/noop-method-call.stderr | 28 +++++++++------------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index e91dd37d8aaae..1aa4a986cd1fe 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -39,7 +39,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // We only care about method calls - if let ExprKind::MethodCall(call, ..) = expr.kind { + if let ExprKind::MethodCall(call, _, elements, _) = expr.kind { // Get the `DefId` only when dealing with an `AssocFn` if let Some((DefKind::AssocFn, did)) = cx.typeck_results().type_dependent_def(expr.hir_id) @@ -70,15 +70,23 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { .iter() .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) { + let method = &call.ident.name; + let receiver = &elements[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver); let expr_span = expr.span; + let note = format!( + "the type `{:?}` which `{}` is being called on is the same as the type returned from `{}`, \ + so the method call does not do anything and can be removed.", + receiver_ty, method, method + ); - cx.struct_span_lint(NOOP_METHOD_CALL, expr_span, |lint| { + let span = expr_span.with_lo(receiver.span.hi()); + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { let method = &call.ident.name; let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); lint.build(&message) - .span_label(expr_span, "unnecessary method call") - .note("the type the method is being called on and the return type are functionally equivalent.") - .note("therefore, the method call doesn't actually do anything and can be removed.") + .span_label(span, "unnecessary method call") + .note(¬e) .emit() }); } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index f9cc9735d54f6..7e27bf3abf9f3 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,39 +1,35 @@ warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:24:32 + --> $DIR/noop-method-call.rs:24:35 | LL | let foo_clone: &Foo = foo.clone(); - | ^^^^^^^^^^^ unnecessary method call + | ^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. warning: call to `.deref()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:31:39 + --> $DIR/noop-method-call.rs:31:44 | LL | let derefed: &DerefExample = deref.deref(); - | ^^^^^^^^^^^^^ unnecessary method call + | ^^^^^^^^ unnecessary method call | - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&&DerefExample` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed. warning: call to `.borrow()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:38:31 + --> $DIR/noop-method-call.rs:38:32 | LL | let borrowed: &Foo = a.borrow(); - | ^^^^^^^^^^ unnecessary method call + | ^^^^^^^^^ unnecessary method call | - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&&Foo` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed. warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:47:5 + --> $DIR/noop-method-call.rs:47:8 | LL | foo.clone(); - | ^^^^^^^^^^^ unnecessary method call + | ^^^^^^^^ unnecessary method call | - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. warning: 4 warnings emitted From 59577b89a6bc4188854c170398f2499fe4e51beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 Jan 2021 18:37:32 -0800 Subject: [PATCH 15/23] Increase accuracy of lint trigger --- compiler/rustc_lint/src/noop_method_call.rs | 58 +++++++++++++-------- src/test/ui/lint/noop-method-call.rs | 3 ++ src/test/ui/lint/noop-method-call.stderr | 10 ++-- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 1aa4a986cd1fe..04d87dc959273 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -62,33 +62,45 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // Resolve the trait method instance if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { // Check that it implements the noop diagnostic - if [ - sym::noop_method_borrow, - sym::noop_method_clone, - sym::noop_method_deref, + for (s, peel_ref) in [ + (sym::noop_method_borrow, true), + (sym::noop_method_clone, false), + (sym::noop_method_deref, true), ] .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) { - let method = &call.ident.name; - let receiver = &elements[0]; - let receiver_ty = cx.typeck_results().expr_ty(receiver); - let expr_span = expr.span; - let note = format!( - "the type `{:?}` which `{}` is being called on is the same as the type returned from `{}`, \ - so the method call does not do anything and can be removed.", - receiver_ty, method, method - ); - - let span = expr_span.with_lo(receiver.span.hi()); - cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + if cx.tcx.is_diagnostic_item(*s, i.def_id()) { let method = &call.ident.name; - let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); - lint.build(&message) - .span_label(span, "unnecessary method call") - .note(¬e) - .emit() - }); + let receiver = &elements[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + let receiver_ty = match receiver_ty.kind() { + // Remove one borrow from the receiver as all the trait methods + // we care about here have a `&self` receiver. + ty::Ref(_, ty, _) if *peel_ref => ty, + _ => receiver_ty, + }; + let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); + if receiver_ty != expr_ty { + return; + } + let expr_span = expr.span; + let note = format!( + "the type `{:?}` which `{}` is being called on is the same as \ + the type returned from `{}`, so the method call does not do \ + anything and can be removed", + receiver_ty, method, method, + ); + + let span = expr_span.with_lo(receiver.span.hi()); + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + let method = &call.ident.name; + let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); + lint.build(&message) + .span_label(span, "unnecessary method call") + .note(¬e) + .emit() + }); + } } } } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index bc61d619abe82..70363a191e9e9 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -37,6 +37,9 @@ fn main() { let a = &&Foo(1u32); let borrowed: &Foo = a.borrow(); //~^ WARNING call to `.borrow()` on a reference in this situation does nothing + + let xs = ["a", "b", "c"]; + let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead } fn generic(foo: &Foo) { diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 7e27bf3abf9f3..316c47975e6de 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -5,7 +5,7 @@ LL | let foo_clone: &Foo = foo.clone(); | ^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default - = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed warning: call to `.deref()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:31:44 @@ -13,7 +13,7 @@ warning: call to `.deref()` on a reference in this situation does nothing LL | let derefed: &DerefExample = deref.deref(); | ^^^^^^^^ unnecessary method call | - = note: the type `&&DerefExample` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed. + = note: the type `&DerefExample` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed warning: call to `.borrow()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:38:32 @@ -21,15 +21,15 @@ warning: call to `.borrow()` on a reference in this situation does nothing LL | let borrowed: &Foo = a.borrow(); | ^^^^^^^^^ unnecessary method call | - = note: the type `&&Foo` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed. + = note: the type `&Foo` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:47:8 + --> $DIR/noop-method-call.rs:50:8 | LL | foo.clone(); | ^^^^^^^^ unnecessary method call | - = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed warning: 4 warnings emitted From af88b7311def8ad39ae958360749e97f1a4aaec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Jan 2021 10:39:25 -0800 Subject: [PATCH 16/23] Clean up code rightward drift --- compiler/rustc_lint/src/noop_method_call.rs | 144 +++++++++++--------- 1 file changed, 79 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 04d87dc959273..b4ee1f9157c82 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -38,73 +38,87 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // We only care about method calls - if let ExprKind::MethodCall(call, _, elements, _) = expr.kind { - // Get the `DefId` only when dealing with an `AssocFn` - if let Some((DefKind::AssocFn, did)) = - cx.typeck_results().type_dependent_def(expr.hir_id) - { - // Check that we're dealing with a trait method - if let Some(trait_id) = cx.tcx.trait_of_item(did) { - // Check we're dealing with one of the traits we care about - if ![sym::Clone, sym::Deref, sym::Borrow] + // We only care about method calls. + let (call, elements) = match expr.kind { + ExprKind::MethodCall(call, _, elements, _) => (call, elements), + _ => return, + }; + // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow` + // traits and ignore any other method call. + let (trait_id, did) = match cx.typeck_results().type_dependent_def(expr.hir_id) { + // Verify we are dealing with a method/associated function. + Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { + // Check that we're dealing with a trait method for one of the traits we care about. + Some(trait_id) + if [sym::Clone, sym::Deref, sym::Borrow] .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) - { - return; - } - - let substs = cx.typeck_results().node_substs(expr.hir_id); - // We can't resolve on types that require monomorphization, - // so check that we don't need to perfom substitution - if !substs.needs_subst() { - let param_env = cx.tcx.param_env(trait_id); - // Resolve the trait method instance - if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { - // Check that it implements the noop diagnostic - for (s, peel_ref) in [ - (sym::noop_method_borrow, true), - (sym::noop_method_clone, false), - (sym::noop_method_deref, true), - ] - .iter() - { - if cx.tcx.is_diagnostic_item(*s, i.def_id()) { - let method = &call.ident.name; - let receiver = &elements[0]; - let receiver_ty = cx.typeck_results().expr_ty(receiver); - let receiver_ty = match receiver_ty.kind() { - // Remove one borrow from the receiver as all the trait methods - // we care about here have a `&self` receiver. - ty::Ref(_, ty, _) if *peel_ref => ty, - _ => receiver_ty, - }; - let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); - if receiver_ty != expr_ty { - return; - } - let expr_span = expr.span; - let note = format!( - "the type `{:?}` which `{}` is being called on is the same as \ - the type returned from `{}`, so the method call does not do \ - anything and can be removed", - receiver_ty, method, method, - ); - - let span = expr_span.with_lo(receiver.span.hi()); - cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let method = &call.ident.name; - let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); - lint.build(&message) - .span_label(span, "unnecessary method call") - .note(¬e) - .emit() - }); - } - } - } - } + .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => + { + (trait_id, did) } + _ => return, + }, + _ => return, + }; + let substs = cx.typeck_results().node_substs(expr.hir_id); + if substs.needs_subst() { + // We can't resolve on types that require monomorphization, so we don't handle them if + // we need to perfom substitution. + return; + } + let param_env = cx.tcx.param_env(trait_id); + // Resolve the trait method instance. + let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) { + Ok(Some(i)) => i, + _ => return, + }; + // (Re)check that it implements the noop diagnostic. + for (s, peel_ref) in [ + (sym::noop_method_borrow, true), + (sym::noop_method_clone, false), + (sym::noop_method_deref, true), + ] + .iter() + { + if cx.tcx.is_diagnostic_item(*s, i.def_id()) { + let method = &call.ident.name; + let receiver = &elements[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + let receiver_ty = match receiver_ty.kind() { + // Remove one borrow from the receiver if appropriate to positively verify that + // the receiver `&self` type and the return type are the same, depending on the + // involved trait being checked. + ty::Ref(_, ty, _) if *peel_ref => ty, + // When it comes to `Clone` we need to check the `receiver_ty` directly. + // FIXME: we must come up with a better strategy for this. + _ => receiver_ty, + }; + let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); + if receiver_ty != expr_ty { + // This lint will only trigger if the receiver type and resulting expression \ + // type are the same, implying that the method call is unnecessary. + return; + } + let expr_span = expr.span; + let note = format!( + "the type `{:?}` which `{}` is being called on is the same as \ + the type returned from `{}`, so the method call does not do \ + anything and can be removed", + receiver_ty, method, method, + ); + + let span = expr_span.with_lo(receiver.span.hi()); + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + let method = &call.ident.name; + let message = format!( + "call to `.{}()` on a reference in this situation does nothing", + &method, + ); + lint.build(&message) + .span_label(span, "unnecessary method call") + .note(¬e) + .emit() + }); } } } From 5ea1d0e865e3a15c054233198622b711ed0b5f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 14 Jan 2021 00:00:00 +0000 Subject: [PATCH 17/23] Don't ICE when computing a layout of a generator tainted by errors --- .../src/debuginfo/metadata.rs | 5 ++-- compiler/rustc_middle/src/ty/layout.rs | 6 ++-- compiler/rustc_middle/src/ty/mod.rs | 6 ++-- compiler/rustc_middle/src/ty/sty.rs | 4 +-- src/test/ui/generator/layout-error.rs | 28 +++++++++++++++++++ src/test/ui/generator/layout-error.stderr | 9 ++++++ 6 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/generator/layout-error.rs create mode 100644 src/test/ui/generator/layout-error.stderr diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 36a21b38c035d..b9ae796325023 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1832,8 +1832,9 @@ impl<'tcx> VariantInfo<'_, 'tcx> { fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option> { match self { VariantInfo::Generator { def_id, variant_index, .. } => { - let span = - cx.tcx.generator_layout(*def_id).variant_source_info[*variant_index].span; + let span = cx.tcx.generator_layout(*def_id).unwrap().variant_source_info + [*variant_index] + .span; if !span.is_dummy() { let loc = cx.lookup_debug_loc(span.lo()); return Some(SourceInfo { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 4475d4e9f2dea..195e840866aec 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1466,10 +1466,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { ) -> Result<&'tcx Layout, LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = self.tcx; - let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs); - let info = tcx.generator_layout(def_id); + let info = match tcx.generator_layout(def_id) { + None => return Err(LayoutError::Unknown(ty)), + Some(info) => info, + }; let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info); // Build a prefix layout, including "promoting" all ineligible diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8068574a38f40..1399fc76e02d6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -3068,8 +3068,10 @@ impl<'tcx> TyCtxt<'tcx> { self.trait_def(trait_def_id).has_auto_impl } - pub fn generator_layout(self, def_id: DefId) -> &'tcx GeneratorLayout<'tcx> { - self.optimized_mir(def_id).generator_layout.as_ref().unwrap() + /// Returns layout of a generator. Layout might be unavailable if the + /// generator is tainted by errors. + pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tcx>> { + self.optimized_mir(def_id).generator_layout.as_ref() } /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 744c7a541a53c..d43c5135d90d5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -605,7 +605,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { #[inline] pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range { // FIXME requires optimized MIR - let num_variants = tcx.generator_layout(def_id).variant_fields.len(); + let num_variants = tcx.generator_layout(def_id).unwrap().variant_fields.len(); VariantIdx::new(0)..VariantIdx::new(num_variants) } @@ -666,7 +666,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { def_id: DefId, tcx: TyCtxt<'tcx>, ) -> impl Iterator> + Captures<'tcx>> { - let layout = tcx.generator_layout(def_id); + let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| layout.field_tys[*field].subst(tcx, self.substs)) }) diff --git a/src/test/ui/generator/layout-error.rs b/src/test/ui/generator/layout-error.rs new file mode 100644 index 0000000000000..059867277ad43 --- /dev/null +++ b/src/test/ui/generator/layout-error.rs @@ -0,0 +1,28 @@ +// Verifies that computing a layout of a generator tainted by type errors +// doesn't ICE. Regression test for #80998. +// +// edition:2018 + +#![feature(type_alias_impl_trait)] +use std::future::Future; + +pub struct Task(F); +impl Task { + fn new() -> Self { + todo!() + } + fn spawn(&self, _: impl FnOnce() -> F) { + todo!() + } +} + +fn main() { + async fn cb() { + let a = Foo; //~ ERROR cannot find value `Foo` in this scope + } + + type F = impl Future; + // Check that statics are inhabited computes they layout. + static POOL: Task = Task::new(); + Task::spawn(&POOL, || cb()); +} diff --git a/src/test/ui/generator/layout-error.stderr b/src/test/ui/generator/layout-error.stderr new file mode 100644 index 0000000000000..b1a258f4f2ca7 --- /dev/null +++ b/src/test/ui/generator/layout-error.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `Foo` in this scope + --> $DIR/layout-error.rs:21:17 + | +LL | let a = Foo; + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From a56bffb4f9d6f7791b2fa40412bd3e0549d76cc3 Mon Sep 17 00:00:00 2001 From: LingMan Date: Mon, 11 Jan 2021 20:45:33 +0100 Subject: [PATCH 18/23] Use Option::map_or instead of `.map(..).unwrap_or(..)` --- compiler/rustc_ast_lowering/src/path.rs | 2 +- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 3 +-- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_data_structures/src/profiling.rs | 2 +- compiler/rustc_driver/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 4 ++-- compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- compiler/rustc_expand/src/mbe/quoted.rs | 6 +++--- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_lint/src/types.rs | 3 +-- compiler/rustc_lint/src/unused.rs | 4 ++-- compiler/rustc_macros/src/query.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 5 ++--- compiler/rustc_middle/src/ty/consts/kind.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 4 ++-- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_mir/src/borrow_check/borrow_set.rs | 2 +- .../src/borrow_check/diagnostics/explain_borrow.rs | 2 +- compiler/rustc_mir/src/interpret/eval_context.rs | 2 +- compiler/rustc_mir/src/interpret/util.rs | 3 +-- compiler/rustc_mir/src/monomorphize/partitioning/mod.rs | 3 +-- compiler/rustc_mir/src/transform/simplify_try.rs | 4 ++-- compiler/rustc_mir_build/src/thir/pattern/usefulness.rs | 2 +- compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 4 ++-- compiler/rustc_query_system/src/dep_graph/graph.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/late/diagnostics.rs | 5 ++--- compiler/rustc_resolve/src/lib.rs | 4 ++-- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_session/src/session.rs | 2 +- compiler/rustc_span/src/source_map.rs | 4 ++-- compiler/rustc_span/src/source_map/tests.rs | 2 +- .../src/traits/error_reporting/mod.rs | 2 +- compiler/rustc_typeck/src/check/check.rs | 4 ++-- compiler/rustc_typeck/src/check/compare_method.rs | 5 +++-- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 5 ++--- compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 4 ++-- compiler/rustc_typeck/src/check/method/suggest.rs | 8 ++------ compiler/rustc_typeck/src/check/wfcheck.rs | 2 +- compiler/rustc_typeck/src/collect.rs | 2 +- compiler/rustc_typeck/src/mem_categorization.rs | 4 +--- compiler/rustc_typeck/src/outlives/implicit_infer.rs | 2 +- 50 files changed, 67 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 9325d4c413941..9079e26eb509e 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -273,7 +273,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if !generic_args.parenthesized && !has_lifetimes { generic_args.args = self .elided_path_lifetimes( - first_generic_span.map(|s| s.shrink_to_lo()).unwrap_or(segment.ident.span), + first_generic_span.map_or(segment.ident.span, |s| s.shrink_to_lo()), expected_lifetimes, ) .map(GenericArg::Lifetime) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d65bc820f8fb1..7bd805f91c857 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -370,7 +370,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!( &self, negative_impls, - span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(span)), + span.to(of_trait.as_ref().map_or(span, |t| t.path.span)), "negative trait bounds are not yet fully implemented; \ use marker types for now" ); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 68f319ade1e79..e225730dce061 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1002,8 +1002,7 @@ pub unsafe fn with_llvm_pmb( // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_size = - config.opt_size.map(|x| to_llvm_opt_settings(x).1).unwrap_or(llvm::CodeGenOptSizeNone); + let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1); let inline_threshold = config.inline_threshold; let pgo_gen_path = get_pgo_gen_path(config); let pgo_use_path = get_pgo_use_path(config); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 728795cf50b85..ff77db9eab852 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -166,7 +166,7 @@ fn get_linker( _ => match flavor { LinkerFlavor::Lld(f) => Command::lld(linker, f), LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => { - Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker)) + Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path())) } _ => Command::new(linker), }, diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 5d13b7f27c704..b16d5a9e2b421 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -166,7 +166,7 @@ impl SelfProfilerRef { // If there is no SelfProfiler then the filter mask is set to NONE, // ensuring that nothing ever tries to actually access it. let event_filter_mask = - profiler.as_ref().map(|p| p.event_filter_mask).unwrap_or(EventFilter::empty()); + profiler.as_ref().map_or(EventFilter::empty(), |p| p.event_filter_mask); SelfProfilerRef { profiler, diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 509f81e16536b..aede631849aed 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1236,7 +1236,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { } // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); + let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); let num_frames = if backtrace { None } else { Some(2) }; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 593e0d92031ff..e184e929b0745 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -804,7 +804,7 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false) + self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c) } fn print_error_count(&mut self, registry: &Registry) { @@ -913,7 +913,7 @@ impl HandlerInner { // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before // incrementing `err_count` by one, so we need to +1 the comparing. // FIXME: Would be nice to increment err_count in a more coherent way. - if self.flags.treat_err_as_bug.map(|c| self.err_count() + 1 >= c).unwrap_or(false) { + if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c) { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 1193f66651ce9..b07bce94870c1 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -423,7 +423,7 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { + if !self.features.map_or(true, |features| features.stmt_expr_attributes) { let mut err = feature_err( &self.sess.parse_sess, sym::stmt_expr_attributes, diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index e76cc6f1fed7b..1aed42a24e2b3 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -500,7 +500,7 @@ fn inner_parse_loop<'root, 'tt>( if idx == len && item.sep.is_some() { // We have a separator, and it is the current token. We can advance past the // separator token. - if item.sep.as_ref().map(|sep| token_name_eq(token, sep)).unwrap_or(false) { + if item.sep.as_ref().map_or(false, |sep| token_name_eq(token, sep)) { item.idx += 1; next_items.push(item); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 3d126749d541d..8373304ea9134 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -203,7 +203,7 @@ fn macro_rules_dummy_expander<'cx>( } fn trace_macros_note(cx_expansions: &mut FxHashMap>, sp: Span, message: String) { - let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); + let sp = sp.macro_backtrace().last().map_or(sp, |trace| trace.call_site); cx_expansions.entry(sp).or_default().push(message); } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index a4b44931fc1ae..c8049495d223c 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -99,10 +99,10 @@ pub(super) fn parse( } _ => token.span, }, - tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span), + tree => tree.as_ref().map_or(span, tokenstream::TokenTree::span), } } - tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), + tree => tree.as_ref().map_or(start_sp, tokenstream::TokenTree::span), }; if node_id != DUMMY_NODE_ID { // Macros loaded from other crates have dummy node ids. @@ -250,7 +250,7 @@ fn parse_kleene_op( Some(op) => Ok(Ok((op, token.span))), None => Ok(Err(token)), }, - tree => Err(tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span)), + tree => Err(tree.as_ref().map_or(span, tokenstream::TokenTree::span)), } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index af6b0a22d4b29..3673e5c8bf3a5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -561,7 +561,7 @@ impl WhereClause<'_> { /// in `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. pub fn tail_span_for_suggestion(&self) -> Span { let end = self.span_for_predicates_or_empty_place().shrink_to_hi(); - self.predicates.last().map(|p| p.span()).unwrap_or(end).shrink_to_hi().to(end) + self.predicates.last().map_or(end, |p| p.span()).shrink_to_hi().to(end) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5d56744805f89..fee6f87ae42c3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2118,7 +2118,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let consider = format!( "{} {}...", msg, - if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) { + if type_param_span.map_or(false, |(_, _, is_impl_trait)| is_impl_trait) { format!(" `{}` to `{}`", sub, bound_kind) } else { format!("`{}: {}`", bound_kind, sub) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 56d9634213ae5..27545c126857b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1533,7 +1533,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Note: if these two lines are combined into one we get // dynamic borrow errors on `self.inner`. let known = self.inner.borrow_mut().type_variables().probe(v).known(); - known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ) + known.map_or(typ, |t| self.shallow_resolve_ty(t)) } ty::Infer(ty::IntVar(v)) => self diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9ad9d53cd0db3..424f91b3f883e 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -647,8 +647,7 @@ pub fn transparent_newtype_field<'a, 'tcx>( let param_env = tcx.param_env(variant.def_id); for field in &variant.fields { let field_ty = tcx.type_of(field.did); - let is_zst = - tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false); + let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst()); if !is_zst { return Some(field); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 35915dc7a9753..bc7363a69a6e8 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -529,8 +529,8 @@ trait UnusedDelimLint { pprust::expr_to_string(value) }; let keep_space = ( - left_pos.map(|s| s >= value.span.lo()).unwrap_or(false), - right_pos.map(|s| s <= value.span.hi()).unwrap_or(false), + left_pos.map_or(false, |s| s >= value.span.lo()), + right_pos.map_or(false, |s| s <= value.span.hi()), ); self.emit_unused_delims(cx, value.span, &expr_text, ctx.into(), keep_space); } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 6d876784be653..d264462bf0895 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -429,7 +429,7 @@ fn add_query_description_impl( }; let (tcx, desc) = modifiers.desc; - let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ }); + let tcx = tcx.as_ref().map_or(quote! { _ }, |t| quote! { #t }); let desc = quote! { #[allow(unused_variables)] diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 019ca5174a223..a7bf79d7e6743 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -326,7 +326,7 @@ impl<'a> CrateLoader<'a> { self.verify_no_symbol_conflicts(&crate_root)?; let private_dep = - self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false); + self.sess.opts.externs.get(&name.as_str()).map_or(false, |e| e.is_private_dep); // Claim this crate number and cache it let cnum = self.cstore.alloc_new_crate_num(); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 5b33678b25ae2..8d0994320e383 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -132,7 +132,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { impl Collector<'tcx> { fn register_native_lib(&mut self, span: Option, lib: NativeLib) { - if lib.name.as_ref().map(|&s| s == kw::Empty).unwrap_or(false) { + if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) { match span { Some(span) => { struct_span_err!( diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 6641606f1e89e..06bb1347dc1de 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -815,7 +815,7 @@ impl<'hir> Map<'hir> { /// Given a node ID, gets a list of attributes associated with the AST /// corresponding to the node-ID. pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { - let attrs = self.find_entry(id).map(|entry| match entry.node { + self.find_entry(id).map_or(&[], |entry| match entry.node { Node::Param(a) => &a.attrs[..], Node::Local(l) => &l.attrs[..], Node::Item(i) => &i.attrs[..], @@ -842,8 +842,7 @@ impl<'hir> Map<'hir> { | Node::Block(..) | Node::Lifetime(..) | Node::Visibility(..) => &[], - }); - attrs.unwrap_or(&[]) + }) } /// Gets the span of the definition of the specified HIR node. diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index ecf2837b3e423..a2638d8bddad0 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -82,7 +82,7 @@ impl<'tcx> ConstKind<'tcx> { /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { - self.try_eval(tcx, param_env).and_then(Result::ok).map(ConstKind::Value).unwrap_or(self) + self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value) } #[inline] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3540f0f06b6e6..c3ad4c1c126d2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1338,7 +1338,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn serialize_query_result_cache(self, encoder: &mut FileEncoder) -> FileEncodeResult { - self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(())) + self.queries.on_disk_cache.as_ref().map_or(Ok(()), |c| c.serialize(self, encoder)) } /// If `true`, we should use the MIR-based borrowck, but also @@ -2601,7 +2601,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner).map(|set| set.contains(&id.local_id)).unwrap_or(false) + self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id)) } pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 413c9cca589d9..6ca5dcc532d22 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -535,7 +535,7 @@ fn polymorphize<'tcx>( } else { None }; - let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false); + let has_upvars = upvars_ty.map_or(false, |ty| ty.tuple_fields().count() > 0); debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars); struct PolymorphizationFolder<'tcx> { diff --git a/compiler/rustc_mir/src/borrow_check/borrow_set.rs b/compiler/rustc_mir/src/borrow_check/borrow_set.rs index b4299fbc5a1fe..288eda32e414e 100644 --- a/compiler/rustc_mir/src/borrow_check/borrow_set.rs +++ b/compiler/rustc_mir/src/borrow_check/borrow_set.rs @@ -149,7 +149,7 @@ impl<'tcx> BorrowSet<'tcx> { } crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] { - self.activation_map.get(&location).map(|activations| &activations[..]).unwrap_or(&[]) + self.activation_map.get(&location).map_or(&[], |activations| &activations[..]) } crate fn len(&self) -> usize { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index eccb6168229c2..a3d09c3a8d4c1 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -75,7 +75,7 @@ impl BorrowExplanation { LaterUseKind::FakeLetRead => "stored here", LaterUseKind::Other => "used here", }; - if !borrow_span.map(|sp| sp.overlaps(var_or_use_span)).unwrap_or(false) { + if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { err.span_label( var_or_use_span, format!("{}borrow later {}", borrow_desc, message), diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 6d7781671d8cc..7e9594dd6bfd7 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -370,7 +370,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn cur_span(&self) -> Span { - self.stack().last().map(|f| f.current_span()).unwrap_or(self.tcx.span) + self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } #[inline(always)] diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index c2165db278fa0..89f34cd07aa4b 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -47,8 +47,7 @@ where let index = index .try_into() .expect("more generic parameters than can fit into a `u32`"); - let is_used = - unused_params.contains(index).map(|unused| !unused).unwrap_or(true); + let is_used = unused_params.contains(index).map_or(true, |unused| !unused); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. match (is_used, subst.needs_subst()) { diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index db6d3b2d912d6..b9fcd32250dcf 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -247,8 +247,7 @@ where for (mono_item, linkage) in cgu.items() { let symbol_name = mono_item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); - let symbol_hash = - symbol_hash_start.map(|i| &symbol_name[i..]).unwrap_or(""); + let symbol_hash = symbol_hash_start.map_or("", |i| &symbol_name[i..]); debug!( " - {} [{:?}] [{}] estimated size {}", diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index a3459887a9a75..05a88828070fb 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -113,7 +113,7 @@ fn get_arm_identity_info<'a, 'tcx>( test: impl Fn(&'a Statement<'tcx>) -> bool, mut action: impl FnMut(usize, &'a Statement<'tcx>), ) { - while stmt_iter.peek().map(|(_, stmt)| test(stmt)).unwrap_or(false) { + while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) { let (idx, stmt) = stmt_iter.next().unwrap(); action(idx, stmt); @@ -635,7 +635,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }) .peekable(); - let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(&targets_and_values[0]); + let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx); let mut all_successors_equivalent = StatementEquality::TrivialEqual; // All successor basic blocks must be equal or contain statements that are pairwise considered equal. diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 83fee380ccce7..d7c08a2d1af6b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -952,7 +952,7 @@ fn is_useful<'p, 'tcx>( assert!(rows.iter().all(|r| r.len() == v.len())); // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). - let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); + let ty = matrix.heads().next().map_or(v.head().ty, |r| r.ty); let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 98c7b9a63a55f..35435baea7019 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -511,7 +511,7 @@ impl<'a> Parser<'a> { // // `x.foo::>>(3)` let parsed_angle_bracket_args = - segment.args.as_ref().map(|args| args.is_angle_bracketed()).unwrap_or(false); + segment.args.as_ref().map_or(false, |args| args.is_angle_bracketed()); debug!( "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}", diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 25e3e67e28e6c..f7b16bd991bfd 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -347,7 +347,7 @@ impl<'a> Parser<'a> { let mut pos = pos; // This handles the raw string case, the raw argument is the number of # // in r###"..."### (we need to add one because of the `r`). - let raw = self.style.map(|raw| raw + 1).unwrap_or(0); + let raw = self.style.map_or(0, |raw| raw + 1); for skip in &self.skips { if pos > *skip { pos += 1; @@ -814,7 +814,7 @@ fn find_skips_from_snippet( skips } - let r_start = str_style.map(|r| r + 1).unwrap_or(0); + let r_start = str_style.map_or(0, |r| r + 1); let r_end = str_style.unwrap_or(0); let s = &snippet[r_start + 1..snippet.len() - r_end - 1]; (find_skips(s, str_style.is_some()), true) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 605d7ae4af678..151e056a5b356 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -953,7 +953,7 @@ impl DepGraph { // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions pub fn is_green(&self, dep_node: &DepNode) -> bool { - self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) + self.node_color(dep_node).map_or(false, |c| c.is_green()) } // This method loads all on-disk cacheable query results into memory, so diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6219d1b08eb68..9de35a8006123 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1925,7 +1925,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { { // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8` let item_span = - path.iter().last().map(|segment| segment.ident.span).unwrap_or(span); + path.iter().last().map_or(span, |segment| segment.ident.span); let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); hm.insert(item_span, span); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 55623c9bd9cf6..3945afb4724a8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -264,7 +264,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // The current function has a `self' parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we // are resolving came from a different hygiene context. - if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) { + if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) { err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters"); } else { let doesnt = if is_assoc_fn { @@ -1452,8 +1452,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } else { let needs_placeholder = |def_id: DefId, kind: CtorKind| { - let has_no_fields = - self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); + let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty()); match kind { CtorKind::Const => false, CtorKind::Fn | CtorKind::Fictive if has_no_fields => false, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fb364053e241e..c5b8f7d647ca7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1052,7 +1052,7 @@ pub struct ResolverArenas<'a> { impl<'a> ResolverArenas<'a> { fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> { let module = self.modules.alloc(module); - if module.def_id().map(|def_id| def_id.is_local()).unwrap_or(true) { + if module.def_id().map_or(true, |def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } module @@ -3031,7 +3031,7 @@ impl<'a> Resolver<'a> { let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); let from_item = - self.extern_prelude.get(&ident).map(|entry| entry.introduced_by_item).unwrap_or(true); + self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by a item. diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index c8cdff4f7e5d3..129123349a028 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -670,7 +670,7 @@ impl<'tcx> SaveContext<'tcx> { ) -> Option { // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`. fn fn_type(seg: &hir::PathSegment<'_>) -> bool { - seg.args.map(|args| args.parenthesized).unwrap_or(false) + seg.args.map_or(false, |args| args.parenthesized) } let res = self.get_path_res(id); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1f9a1af0f6872..6d01854228662 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1358,7 +1358,7 @@ pub fn build_session( let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); let optimization_fuel = Lock::new(OptimizationFuel { - remaining: sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0), + remaining: sopts.debugging_opts.fuel.as_ref().map_or(0, |i| i.1), out_of_fuel: false, }); let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 842ccda6ea8b0..4e0ce0d344de4 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -539,7 +539,7 @@ impl SourceMap { pub fn is_line_before_span_empty(&self, sp: Span) -> bool { match self.span_to_prev_source(sp) { - Ok(s) => s.split('\n').last().map(|l| l.trim_start().is_empty()).unwrap_or(false), + Ok(s) => s.split('\n').last().map_or(false, |l| l.trim_start().is_empty()), Err(_) => false, } } @@ -568,7 +568,7 @@ impl SourceMap { // asserting that the line numbers here are all indeed 1-based. let hi_line = hi.line.saturating_sub(1); for line_index in lo.line.saturating_sub(1)..hi_line { - let line_len = lo.file.get_line(line_index).map(|s| s.chars().count()).unwrap_or(0); + let line_len = lo.file.get_line(line_index).map_or(0, |s| s.chars().count()); lines.push(LineInfo { line_index, start_col, end_col: CharPos::from_usize(line_len) }); start_col = CharPos::from_usize(0); } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index b8459eee4ecf0..3f22829b049fe 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -107,7 +107,7 @@ fn t7() { fn span_from_selection(input: &str, selection: &str) -> Span { assert_eq!(input.len(), selection.len()); let left_index = selection.find('~').unwrap() as u32; - let right_index = selection.rfind('~').map(|x| x as u32).unwrap_or(left_index); + let right_index = selection.rfind('~').map_or(left_index, |x| x as u32); Span::with_root_ctxt(BytePos(left_index), BytePos(right_index + 1)) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 0186d164a4c53..795cf2e19decc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -830,7 +830,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .collect::>(), ), Node::Ctor(ref variant_data) => { - let span = variant_data.ctor_hir_id().map(|id| hir.span(id)).unwrap_or(DUMMY_SP); + let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); let span = sm.guess_head_span(span); (span, vec![ArgKind::empty(); variant_data.fields().len()]) } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index f1fb2b800232d..8e339eb26b26c 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1259,8 +1259,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty let layout = tcx.layout_of(param_env.and(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir().span_if_local(field.did).unwrap(); - let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); - let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); + let zst = layout.map_or(false, |layout| layout.is_zst()); + let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1); (span, zst, align1) }); diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 320ded5334e21..0036edda36da5 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -364,13 +364,14 @@ fn check_region_bounds_on_impl_item<'tcx>( if trait_params != impl_params { let item_kind = assoc_item_kind_str(impl_m); let def_span = tcx.sess.source_map().guess_head_span(span); - let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span); + let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span); let generics_span = if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { let def_sp = tcx.sess.source_map().guess_head_span(sp); - Some(tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp)) + Some(tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)) } else { None }; + tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { span, item_kind, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index c3166ce8164f4..47799c95fc0a7 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -904,8 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // Return directly on cache hit. This is useful to avoid doubly reporting // errors with default match binding modes. See #44614. - let def = - cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); + let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)); return (def, Some(ty), slice::from_ref(&**item_segment)); } let item_name = item_segment.ident; @@ -932,7 +931,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Write back the new resolution. self.write_resolution(hir_id, result); ( - result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), + result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), Some(ty), slice::from_ref(&**item_segment), ) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 87b8c4889e893..4afa6689b92c7 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -816,7 +816,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(match &elem.kind { // Point at the tail expression when possible. hir::ExprKind::Block(block, _) => { - block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) + block.expr.as_ref().map_or(block.span, |e| e.span) } _ => elem.span, }) @@ -888,7 +888,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Write back the new resolution. self.write_resolution(hir_id, result); - (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) + (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) } QPath::LangItem(lang_item, span) => { self.resolve_lang_item_path(lang_item, span, hir_id) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 5cfd78ebeacad..e6bfa5e1497fe 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1193,7 +1193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .any(|imp_did| { let imp = self.tcx.impl_trait_ref(imp_did).unwrap(); let imp_simp = simplify_type(self.tcx, imp.self_ty(), true); - imp_simp.map(|s| s == simp_rcvr_ty).unwrap_or(false) + imp_simp.map_or(false, |s| s == simp_rcvr_ty) }) { explicitly_negative.push(candidate); @@ -1270,11 +1270,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.kind() { ty::Adt(def, _) => def.did.is_local(), ty::Foreign(did) => did.is_local(), - - ty::Dynamic(ref tr, ..) => { - tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false) - } - + ty::Dynamic(ref tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()), ty::Param(_) => true, // Everything else (primitive types, etc.) is effectively diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index fc3dff2654257..2c720ce025b0b 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -108,7 +108,7 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { .impl_trait_ref(tcx.hir().local_def_id(item.hir_id)) .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id)); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { - let sp = impl_.of_trait.as_ref().map(|t| t.path.span).unwrap_or(item.span); + let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); let mut err = tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default"); err.span_labels(impl_.defaultness_span, "default because of this"); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 1626a0116a7eb..a6677328f8f88 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1656,7 +1656,7 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { .. }) => { if is_rustc_reservation { - let span = span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(*span)); + let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span)); tcx.sess.span_err(span, "reservation impls can't be negative"); } ty::ImplPolarity::Negative diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index 37f9e3d63b830..fef52a3f87c95 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -654,9 +654,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // Then we see that to get the same result, we must start with // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. - for _ in - 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0) - { + for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) { debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id); place_with_id = self.cat_deref(pat, place_with_id)?; } diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 3d0635e3fe437..02008e180b34d 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -99,7 +99,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { // we walk the crates again and re-calculate predicates for all // items. let item_predicates_len: usize = - self.global_inferred_outlives.get(&item_did.to_def_id()).map(|p| p.len()).unwrap_or(0); + self.global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.len()); if item_required_predicates.len() > item_predicates_len { *self.predicates_added = true; self.global_inferred_outlives.insert(item_did.to_def_id(), item_required_predicates); From 744f885e2a505136203e3e0eef51f72dbe78b511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 9 Jan 2021 10:22:06 +0100 Subject: [PATCH 19/23] Remove unreachable panics from VecDeque --- .../alloc/src/collections/vec_deque/mod.rs | 9 ++++----- src/test/codegen/vecdeque_no_panic.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 src/test/codegen/vecdeque_no_panic.rs diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index f8fad6de1a3cc..5b61e8911a59a 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1292,7 +1292,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn front(&self) -> Option<&T> { - if !self.is_empty() { Some(&self[0]) } else { None } + self.get(0) } /// Provides a mutable reference to the front element, or `None` if the @@ -1316,7 +1316,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn front_mut(&mut self) -> Option<&mut T> { - if !self.is_empty() { Some(&mut self[0]) } else { None } + self.get_mut(0) } /// Provides a reference to the back element, or `None` if the `VecDeque` is @@ -1336,7 +1336,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn back(&self) -> Option<&T> { - if !self.is_empty() { Some(&self[self.len() - 1]) } else { None } + self.get(self.len().wrapping_sub(1)) } /// Provides a mutable reference to the back element, or `None` if the @@ -1360,8 +1360,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn back_mut(&mut self) -> Option<&mut T> { - let len = self.len(); - if !self.is_empty() { Some(&mut self[len - 1]) } else { None } + self.get_mut(self.len().wrapping_sub(1)) } /// Removes the first element and returns it, or `None` if the `VecDeque` is diff --git a/src/test/codegen/vecdeque_no_panic.rs b/src/test/codegen/vecdeque_no_panic.rs new file mode 100644 index 0000000000000..cbf420bada994 --- /dev/null +++ b/src/test/codegen/vecdeque_no_panic.rs @@ -0,0 +1,19 @@ +// This test checks that `VecDeque::front[_mut]()` and `VecDeque::back[_mut]()` can't panic. + +// compile-flags: -O +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +// CHECK-LABEL: @dont_panic +#[no_mangle] +pub fn dont_panic(v: &mut VecDeque) { + // CHECK-NOT: expect + // CHECK-NOT: panic + v.front(); + v.front_mut(); + v.back(); + v.back_mut(); +} From 7a0f0b5069609c65892f7e3f43f8e5598b306489 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 14:49:58 -0500 Subject: [PATCH 20/23] Remove doctree::Import --- src/librustdoc/clean/mod.rs | 180 ++++++++++++++++++------------------ src/librustdoc/doctree.rs | 14 --- src/librustdoc/visit_ast.rs | 10 +- 3 files changed, 90 insertions(+), 114 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c74a56599422b..a8beb4a322ccd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -219,7 +219,6 @@ impl Clean for CrateNum { impl Clean for doctree::Module<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let mut items: Vec = vec![]; - items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); items.extend(self.foreigns.iter().map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); items.extend(self.items.iter().map(|x| x.clean(cx)).flatten()); @@ -2032,7 +2031,7 @@ impl Clean> for (&hir::Item<'_>, Option) { ItemKind::Fn(ref sig, ref generics, body_id) => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } - hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { + ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { let items = item_ids .iter() .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)) @@ -2051,6 +2050,9 @@ impl Clean> for (&hir::Item<'_>, Option) { ItemKind::ExternCrate(orig_name) => { return clean_extern_crate(item, name, orig_name, cx); } + ItemKind::Use(path, kind) => { + return clean_use_statement(item, name, path, kind, cx); + } _ => unreachable!("not yet converted"), }; @@ -2172,105 +2174,101 @@ fn clean_extern_crate( }] } -impl Clean> for doctree::Import<'_> { - fn clean(&self, cx: &DocContext<'_>) -> Vec { - // We need this comparison because some imports (for std types for example) - // are "inserted" as well but directly by the compiler and they should not be - // taken into account. - if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) { - return Vec::new(); - } - - let (doc_meta_item, please_inline) = self.attrs.lists(sym::doc).get_word_attr(sym::inline); - let pub_underscore = self.vis.node.is_pub() && self.name == kw::Underscore; - - if pub_underscore && please_inline { - rustc_errors::struct_span_err!( - cx.tcx.sess, - doc_meta_item.unwrap().span(), - E0780, - "anonymous imports cannot be inlined" - ) - .span_label(self.span, "anonymous import") - .emit(); - } +fn clean_use_statement( + import: &hir::Item<'_>, + name: Symbol, + path: &hir::Path<'_>, + kind: hir::UseKind, + cx: &DocContext<'_>, +) -> Vec { + // We need this comparison because some imports (for std types for example) + // are "inserted" as well but directly by the compiler and they should not be + // taken into account. + if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) { + return Vec::new(); + } + + let (doc_meta_item, please_inline) = import.attrs.lists(sym::doc).get_word_attr(sym::inline); + let pub_underscore = import.vis.node.is_pub() && name == kw::Underscore; + + if pub_underscore && please_inline { + rustc_errors::struct_span_err!( + cx.tcx.sess, + doc_meta_item.unwrap().span(), + E0780, + "anonymous imports cannot be inlined" + ) + .span_label(import.span, "anonymous import") + .emit(); + } - // We consider inlining the documentation of `pub use` statements, but we - // forcefully don't inline if this is not public or if the - // #[doc(no_inline)] attribute is present. - // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let mut denied = !self.vis.node.is_pub() - || pub_underscore - || self.attrs.iter().any(|a| { - a.has_name(sym::doc) - && match a.meta_item_list() { - Some(l) => { - attr::list_contains_name(&l, sym::no_inline) - || attr::list_contains_name(&l, sym::hidden) - } - None => false, + // We consider inlining the documentation of `pub use` statements, but we + // forcefully don't inline if this is not public or if the + // #[doc(no_inline)] attribute is present. + // Don't inline doc(hidden) imports so they can be stripped at a later stage. + let mut denied = !import.vis.node.is_pub() + || pub_underscore + || import.attrs.iter().any(|a| { + a.has_name(sym::doc) + && match a.meta_item_list() { + Some(l) => { + attr::list_contains_name(&l, sym::no_inline) + || attr::list_contains_name(&l, sym::hidden) } - }); - // Also check whether imports were asked to be inlined, in case we're trying to re-export a - // crate in Rust 2018+ - let path = self.path.clean(cx); - let inner = if self.glob { - if !denied { - let mut visited = FxHashSet::default(); - if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { - return items; + None => false, } + }); + + // Also check whether imports were asked to be inlined, in case we're trying to re-export a + // crate in Rust 2018+ + let path = path.clean(cx); + let inner = if kind == hir::UseKind::Glob { + if !denied { + let mut visited = FxHashSet::default(); + if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { + return items; } - Import::new_glob(resolve_use_source(cx, path), true) - } else { - let name = self.name; - if !please_inline { - if let Res::Def(DefKind::Mod, did) = path.res { - if !did.is_local() && did.index == CRATE_DEF_INDEX { - // if we're `pub use`ing an extern crate root, don't inline it unless we - // were specifically asked for it - denied = true; - } + } + Import::new_glob(resolve_use_source(cx, path), true) + } else { + if !please_inline { + if let Res::Def(DefKind::Mod, did) = path.res { + if !did.is_local() && did.index == CRATE_DEF_INDEX { + // if we're `pub use`ing an extern crate root, don't inline it unless we + // were specifically asked for it + denied = true; } } - if !denied { - let mut visited = FxHashSet::default(); + } + if !denied { + let mut visited = FxHashSet::default(); - if let Some(mut items) = inline::try_inline( + if let Some(mut items) = inline::try_inline( + cx, + cx.tcx.parent_module(import.hir_id).to_def_id(), + path.res, + name, + Some(import.attrs), + &mut visited, + ) { + items.push(Item::from_def_id_and_parts( + cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), + None, + ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)), cx, - cx.tcx.parent_module(self.id).to_def_id(), - path.res, - name, - Some(self.attrs), - &mut visited, - ) { - items.push(Item { - name: None, - attrs: box self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), - visibility: self.vis.clean(cx), - kind: box ImportItem(Import::new_simple( - self.name, - resolve_use_source(cx, path), - false, - )), - }); - return items; - } + )); + return items; } - Import::new_simple(name, resolve_use_source(cx, path), true) - }; + } + Import::new_simple(name, resolve_use_source(cx, path), true) + }; - vec![Item { - name: None, - attrs: box self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), - visibility: self.vis.clean(cx), - kind: box ImportItem(inner), - }] - } + vec![Item::from_def_id_and_parts( + cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), + None, + ImportItem(inner), + cx, + )] } impl Clean for (&hir::ForeignItem<'_>, Option) { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index bc9f1cf8806ab..5413f14c7c42a 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -2,7 +2,6 @@ //! manner (and with prettier names) before cleaning. crate use self::StructType::*; -use rustc_ast as ast; use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; @@ -11,7 +10,6 @@ crate struct Module<'hir> { crate name: Option, crate where_outer: Span, crate where_inner: Span, - crate imports: Vec>, crate mods: Vec>, crate id: hir::HirId, // (item, renamed) @@ -28,7 +26,6 @@ impl Module<'hir> { id: hir::CRATE_HIR_ID, where_outer: rustc_span::DUMMY_SP, where_inner: rustc_span::DUMMY_SP, - imports: Vec::new(), mods: Vec::new(), items: Vec::new(), foreigns: Vec::new(), @@ -54,17 +51,6 @@ crate struct Variant<'hir> { crate def: &'hir hir::VariantData<'hir>, } -#[derive(Debug)] -crate struct Import<'hir> { - crate name: Symbol, - crate id: hir::HirId, - crate vis: &'hir hir::Visibility<'hir>, - crate attrs: &'hir [ast::Attribute], - crate path: &'hir hir::Path<'hir>, - crate glob: bool, - crate span: Span, -} - crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType { match *vdata { hir::VariantData::Struct(..) => Plain, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f701352c486ba..7d161ca3648cc 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -316,15 +316,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - om.imports.push(Import { - name, - id: item.hir_id, - vis: &item.vis, - attrs: &item.attrs, - path, - glob: is_glob, - span: item.span, - }); + om.items.push((item, renamed)) } hir::ItemKind::Mod(ref m) => { om.mods.push(self.visit_mod_contents( From 0584ddceb9d0e78a3c64927f1d949f1684fee065 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 15:03:17 -0500 Subject: [PATCH 21/23] Address nit --- src/librustdoc/clean/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a8beb4a322ccd..6327a0fa08383 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2221,6 +2221,7 @@ fn clean_use_statement( // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ + let def_id = cx.tcx.hir().local_def_id(import.hir_id).to_def_id(); let path = path.clean(cx); let inner = if kind == hir::UseKind::Glob { if !denied { @@ -2252,7 +2253,7 @@ fn clean_use_statement( &mut visited, ) { items.push(Item::from_def_id_and_parts( - cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), + def_id, None, ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)), cx, @@ -2263,12 +2264,7 @@ fn clean_use_statement( Import::new_simple(name, resolve_use_source(cx, path), true) }; - vec![Item::from_def_id_and_parts( - cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), - None, - ImportItem(inner), - cx, - )] + vec![Item::from_def_id_and_parts(def_id, None, ImportItem(inner), cx)] } impl Clean for (&hir::ForeignItem<'_>, Option) { From d07bb13a5a84e9bb7662c1dc013a551f1d63d4d4 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 19:01:48 -0500 Subject: [PATCH 22/23] Fix JSON test --- src/test/rustdoc-json/nested.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc-json/nested.expected b/src/test/rustdoc-json/nested.expected index 65bb0c5fa0367..80070e75f1e5e 100644 --- a/src/test/rustdoc-json/nested.expected +++ b/src/test/rustdoc-json/nested.expected @@ -41,8 +41,8 @@ "inner": { "is_crate": false, "items": [ - "0:7", - "0:4" + "0:4", + "0:7" ] }, "kind": "module", From a70813e6ee201bef69b3c174a41eaed55c32913d Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 19:39:59 -0500 Subject: [PATCH 23/23] Add warning to compare.py about error messages --- src/test/rustdoc-json/compare.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py index b0c5b16a19700..6a921266336e0 100644 --- a/src/test/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -7,6 +7,9 @@ # and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. If # you're on windows, replace `\` with `/`. +# WARNING: The error messages produced by this may be misleading, in the case of list re-ordering +# it may point to apparently unrelated keys. + import copy import sys import json