From aef3d938e42bec121304b6c51ad67446c6e171a3 Mon Sep 17 00:00:00 2001 From: Qiu Chaofan <qcf@ecnelises.com> Date: Thu, 25 Aug 2022 14:37:29 +0800 Subject: [PATCH 01/38] Add powerpc64-ibm-aix as Tier-3 target --- compiler/rustc_target/src/spec/aix_base.rs | 32 +++++++++++++++++++ compiler/rustc_target/src/spec/mod.rs | 8 +++++ .../src/spec/powerpc64_ibm_aix.rs | 23 +++++++++++++ src/doc/rustc/src/platform-support.md | 1 + .../ui/check-cfg/well-known-values.stderr | 2 +- 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_target/src/spec/aix_base.rs create mode 100644 compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs diff --git a/compiler/rustc_target/src/spec/aix_base.rs b/compiler/rustc_target/src/spec/aix_base.rs new file mode 100644 index 0000000000000..c71c4ba2cc902 --- /dev/null +++ b/compiler/rustc_target/src/spec/aix_base.rs @@ -0,0 +1,32 @@ +use crate::abi::Endian; +use crate::spec::{crt_objects, cvs, Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions}; + +pub fn opts() -> TargetOptions { + TargetOptions { + abi: "vec-extabi".into(), + code_model: Some(CodeModel::Small), + cpu: "pwr7".into(), + os: "aix".into(), + vendor: "ibm".into(), + dynamic_linking: true, + endian: Endian::Big, + executables: true, + archive_format: "aix_big".into(), + families: cvs!["unix"], + has_rpath: false, + has_thread_local: true, + crt_static_respected: true, + linker_flavor: LinkerFlavor::Unix(Cc::No), + linker: Some("ld".into()), + eh_frame_header: false, + is_like_aix: true, + default_dwarf_version: 3, + function_sections: true, + pre_link_objects: crt_objects::new(&[ + (LinkOutputKind::DynamicNoPicExe, &["/usr/lib/crt0_64.o", "/usr/lib/crti_64.o"]), + (LinkOutputKind::DynamicPicExe, &["/usr/lib/crt0_64.o", "/usr/lib/crti_64.o"]), + ]), + dll_suffix: ".a".into(), + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 664592b02a124..d4b06c46cd752 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -57,6 +57,7 @@ use rustc_macros::HashStable_Generic; pub mod abi; pub mod crt_objects; +mod aix_base; mod android_base; mod apple_base; mod avr_gnu_base; @@ -1026,6 +1027,7 @@ supported_targets! { ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), ("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe), ("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl), + ("powerpc64-ibm-aix", powerpc64_ibm_aix), ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), ("powerpc64-unknown-linux-musl", powerpc64_unknown_linux_musl), ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), @@ -1453,6 +1455,9 @@ pub struct TargetOptions { pub families: StaticCow<[StaticCow<str>]>, /// Whether the target toolchain's ABI supports returning small structs as an integer. pub abi_return_struct_as_int: bool, + /// Whether the target toolchain is like AIX's. Linker options on AIX are special and it uses + /// XCOFF as binary format. Defaults to false. + pub is_like_aix: bool, /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS, /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. /// Also indiates whether to use Apple-specific ABI changes, such as extending function @@ -1808,6 +1813,7 @@ impl Default for TargetOptions { staticlib_suffix: ".a".into(), families: cvs![], abi_return_struct_as_int: false, + is_like_aix: false, is_like_osx: false, is_like_solaris: false, is_like_windows: false, @@ -2465,6 +2471,7 @@ impl Target { key!(staticlib_suffix); key!(families, TargetFamilies); key!(abi_return_struct_as_int, bool); + key!(is_like_aix, bool); key!(is_like_osx, bool); key!(is_like_solaris, bool); key!(is_like_windows, bool); @@ -2716,6 +2723,7 @@ impl ToJson for Target { target_option_val!(staticlib_suffix); target_option_val!(families, "target-family"); target_option_val!(abi_return_struct_as_int); + target_option_val!(is_like_aix); target_option_val!(is_like_osx); target_option_val!(is_like_solaris); target_option_val!(is_like_windows); diff --git a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs new file mode 100644 index 0000000000000..e3eb9bccd5ed7 --- /dev/null +++ b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs @@ -0,0 +1,23 @@ +use crate::spec::{Cc, LinkerFlavor, Target}; + +pub fn target() -> Target { + let mut base = super::aix_base::opts(); + base.max_atomic_width = Some(64); + base.add_pre_link_args( + LinkerFlavor::Unix(Cc::No), + &[ + "-b64".into(), + "-bpT:0x100000000".into(), + "-bpD:0x110000000".into(), + "-bcdtors:all:0:s".into(), + ], + ); + + Target { + llvm_target: "powerpc64-ibm-aix".into(), + pointer_width: 64, + data_layout: "E-m:a-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + arch: "powerpc64".into(), + options: base, + } +} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 28929acb9b48d..27e911c6be5a2 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -283,6 +283,7 @@ target | std | host | notes `powerpc64-wrs-vxworks` | ? | | `powerpc64le-unknown-linux-musl` | ? | | [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64 +`powerpc64-ibm-aix` | ? | | 64-bit AIX (7.2 and newer) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) `riscv32im-unknown-none-elf` | * | | Bare RISC-V (RV32IM ISA) diff --git a/src/test/ui/check-cfg/well-known-values.stderr b/src/test/ui/check-cfg/well-known-values.stderr index 6c0dc05ba2330..29ececea5d394 100644 --- a/src/test/ui/check-cfg/well-known-values.stderr +++ b/src/test/ui/check-cfg/well-known-values.stderr @@ -6,7 +6,7 @@ LL | #[cfg(target_os = "linuz")] | | | help: did you mean: `"linux"` | - = note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous + = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, watchos, windows, xous = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value From 83701f544f461e9dc5d7e9b798b54831a09fece6 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino <spastorino@gmail.com> Date: Wed, 16 Nov 2022 15:58:48 -0300 Subject: [PATCH 02/38] Use ObligationCtxt intead of dyn TraitEngine --- compiler/rustc_hir_typeck/src/coercion.rs | 11 ++++----- .../src/traits/error_reporting/mod.rs | 12 ++++------ .../rustc_trait_selection/src/traits/mod.rs | 19 ++++++++------- .../src/traits/specialize/mod.rs | 12 +++++----- .../src/traits/structural_match.rs | 23 ++++--------------- 5 files changed, 30 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 71949b4211819..cd7f9dff3161e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -46,7 +46,7 @@ use rustc_hir::Expr; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; -use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt}; +use rustc_infer::traits::Obligation; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, @@ -62,8 +62,7 @@ use rustc_span::{self, BytePos, DesugaringKind, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::TraitEngineExt as _; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, ObligationCtxt}; use smallvec::{smallvec, SmallVec}; use std::ops::Deref; @@ -1039,9 +1038,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Ok(ok) = coerce.coerce(source, target) else { return false; }; - let mut fcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx); - fcx.register_predicate_obligations(self, ok.obligations); - fcx.select_where_possible(&self).is_empty() + let ocx = ObligationCtxt::new_in_snapshot(self); + ocx.register_obligations(ok.obligations); + ocx.select_where_possible().is_empty() }) } 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 41b252a82651c..fba4889df9a23 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -4,13 +4,12 @@ pub mod suggestions; use super::{ FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause, - ObligationCauseCode, OutputTypeParameterMismatch, Overflow, PredicateObligation, - SelectionContext, SelectionError, TraitNotObjectSafe, + ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow, + PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe, }; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt, TyCtxtInferExt}; -use crate::traits::engine::TraitEngineExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::AtExt as _; use crate::traits::specialize::to_pretty_impl_header; @@ -29,7 +28,6 @@ use rustc_hir::Item; use rustc_hir::Node; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::TypeTrace; -use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; @@ -353,9 +351,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) .to_predicate(self.tcx), ); - let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.tcx); - fulfill_cx.register_predicate_obligation(self, obligation); - if fulfill_cx.select_all_or_error(self).is_empty() { + let ocx = ObligationCtxt::new_in_snapshot(self); + ocx.register_obligation(obligation); + if ocx.select_all_or_error().is_empty() { return Ok(( ty::ClosureKind::from_def_id(self.tcx, trait_def_id) .expect("expected to map DefId to ClosureKind"), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 10e48610e3abb..4ad90e657f2cd 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -31,7 +31,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ @@ -395,9 +394,9 @@ pub fn fully_solve_obligation<'tcx>( infcx: &InferCtxt<'tcx>, obligation: PredicateObligation<'tcx>, ) -> Vec<FulfillmentError<'tcx>> { - let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx); - engine.register_predicate_obligation(infcx, obligation); - engine.select_all_or_error(infcx) + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligation(obligation); + ocx.select_all_or_error() } /// Process a set of obligations (and any nested obligations that come from them) @@ -406,9 +405,9 @@ pub fn fully_solve_obligations<'tcx>( infcx: &InferCtxt<'tcx>, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, ) -> Vec<FulfillmentError<'tcx>> { - let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx); - engine.register_predicate_obligations(infcx, obligations); - engine.select_all_or_error(infcx) + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligations(obligations); + ocx.select_all_or_error() } /// Process a bound (and any nested obligations that come from it) to completion. @@ -421,9 +420,9 @@ pub fn fully_solve_bound<'tcx>( ty: Ty<'tcx>, bound: DefId, ) -> Vec<FulfillmentError<'tcx>> { - let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx); - engine.register_bound(infcx, param_env, ty, bound, cause); - engine.select_all_or_error(infcx) + let ocx = ObligationCtxt::new(infcx); + ocx.register_bound(cause, param_env, ty, bound); + ocx.select_all_or_error() } /// Normalizes the predicates and checks whether they hold in an empty environment. If this diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 7cc12eff20e8b..9a3c0707c7ce9 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -10,14 +10,14 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html pub mod specialization_graph; -use rustc_infer::traits::{TraitEngine, TraitEngineExt as _}; use specialization_graph::GraphExt; use crate::errors::NegativePositiveConflict; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; -use crate::traits::engine::TraitEngineExt as _; use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause}; +use crate::traits::{ + self, coherence, FutureCompatOverlapErrorKind, ObligationCause, ObligationCtxt, +}; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{error_code, DelayDm, Diagnostic}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -204,12 +204,12 @@ fn fulfill_implication<'tcx>( // Needs to be `in_snapshot` because this function is used to rebase // substitutions, which may happen inside of a select within a probe. - let mut engine = <dyn TraitEngine<'tcx>>::new_in_snapshot(infcx.tcx); + let ocx = ObligationCtxt::new_in_snapshot(infcx); // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) - engine.register_predicate_obligations(infcx, obligations.chain(more_obligations)); + ocx.register_obligations(obligations.chain(more_obligations)); - let errors = engine.select_all_or_error(infcx); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { // no dice! debug!( diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 932dbbb81e5cc..40dbe0b3ff063 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -1,6 +1,5 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; -use crate::traits::ObligationCause; -use crate::traits::{TraitEngine, TraitEngineExt}; +use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -72,28 +71,16 @@ fn type_marked_structural<'tcx>( adt_ty: Ty<'tcx>, cause: ObligationCause<'tcx>, ) -> bool { - let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx); + let ocx = ObligationCtxt::new(infcx); // require `#[derive(PartialEq)]` let structural_peq_def_id = infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span)); - fulfillment_cx.register_bound( - infcx, - ty::ParamEnv::empty(), - adt_ty, - structural_peq_def_id, - cause.clone(), - ); + ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id); // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.) let structural_teq_def_id = infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span)); - fulfillment_cx.register_bound( - infcx, - ty::ParamEnv::empty(), - adt_ty, - structural_teq_def_id, - cause, - ); + ocx.register_bound(cause, ty::ParamEnv::empty(), adt_ty, structural_teq_def_id); // We deliberately skip *reporting* fulfillment errors (via // `report_fulfillment_errors`), for two reasons: @@ -104,7 +91,7 @@ fn type_marked_structural<'tcx>( // // 2. We are sometimes doing future-incompatibility lints for // now, so we do not want unconditional errors here. - fulfillment_cx.select_all_or_error(infcx).is_empty() + ocx.select_all_or_error().is_empty() } /// This implements the traversal over the structure of a given type to try to From 23422a8560dcb78351c1ee0e2eb2d353b5489c91 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino <spastorino@gmail.com> Date: Thu, 17 Nov 2022 11:44:24 -0300 Subject: [PATCH 03/38] Call fully_solve_obligations instead of repeating code --- .../rustc_trait_selection/src/traits/mod.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 4ad90e657f2cd..f11c642d99ffd 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -394,9 +394,7 @@ pub fn fully_solve_obligation<'tcx>( infcx: &InferCtxt<'tcx>, obligation: PredicateObligation<'tcx>, ) -> Vec<FulfillmentError<'tcx>> { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligation(obligation); - ocx.select_all_or_error() + fully_solve_obligations(infcx, [obligation]) } /// Process a set of obligations (and any nested obligations that come from them) @@ -420,9 +418,16 @@ pub fn fully_solve_bound<'tcx>( ty: Ty<'tcx>, bound: DefId, ) -> Vec<FulfillmentError<'tcx>> { - let ocx = ObligationCtxt::new(infcx); - ocx.register_bound(cause, param_env, ty, bound); - ocx.select_all_or_error() + let tcx = infcx.tcx; + let trait_ref = ty::TraitRef { def_id: bound, substs: tcx.mk_substs_trait(ty, &[]) }; + let obligation = Obligation { + cause, + recursion_depth: 0, + param_env, + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + }; + + fully_solve_obligation(infcx, obligation) } /// Normalizes the predicates and checks whether they hold in an empty environment. If this From 9864a6323b3239fc4205eb027c87b3ee11b46569 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino <spastorino@gmail.com> Date: Wed, 16 Nov 2022 19:40:55 -0300 Subject: [PATCH 04/38] Pass ObligationCtxt from enter_canonical_trait_query and use ObligationCtxt API --- .../src/implied_outlives_bounds.rs | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 82f6111f6f92e..35ed80097fb1d 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -5,16 +5,15 @@ use rustc_hir as hir; use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; use rustc_trait_selection::traits::wf; -use rustc_trait_selection::traits::{TraitEngine, TraitEngineExt}; +use rustc_trait_selection::traits::ObligationCtxt; use smallvec::{smallvec, SmallVec}; pub(crate) fn provide(p: &mut Providers) { @@ -30,16 +29,16 @@ fn implied_outlives_bounds<'tcx>( > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ty) = key.into_parts(); - compute_implied_outlives_bounds(&ocx.infcx, param_env, ty) + compute_implied_outlives_bounds(ocx, param_env, ty) }) } fn compute_implied_outlives_bounds<'tcx>( - infcx: &InferCtxt<'tcx>, + ocx: &ObligationCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Fallible<Vec<OutlivesBound<'tcx>>> { - let tcx = infcx.tcx; + let tcx = ocx.infcx.tcx; // Sometimes when we ask what it takes for T: WF, we get back that // U: WF is required; in that case, we push U onto this stack and @@ -52,8 +51,6 @@ fn compute_implied_outlives_bounds<'tcx>( let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> = vec![]; - let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx); - while let Some(arg) = wf_args.pop() { if !checked_wf_args.insert(arg) { continue; @@ -70,15 +67,15 @@ fn compute_implied_outlives_bounds<'tcx>( // FIXME(@lcnr): It's not really "always fine", having fewer implied // bounds can be backward incompatible, e.g. #101951 was caused by // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); + let obligations = + wf::obligations(ocx.infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) + .unwrap_or_default(); // While these predicates should all be implied by other parts of // the program, they are still relevant as they may constrain // inference variables, which is necessary to add the correct // implied bounds in some cases, mostly when dealing with projections. - fulfill_cx.register_predicate_obligations( - infcx, + ocx.register_obligations( obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(), ); @@ -115,9 +112,9 @@ fn compute_implied_outlives_bounds<'tcx>( })); } - // Ensure that those obligations that we had to solve - // get solved *here*. - match fulfill_cx.select_all_or_error(infcx).as_slice() { + // This call to `select_all_or_error` is necessary to constrain inference variables, which we + // use further down when computing the implied bounds. + match ocx.select_all_or_error().as_slice() { [] => (), _ => return Err(NoSolution), } @@ -129,7 +126,7 @@ fn compute_implied_outlives_bounds<'tcx>( .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], ty::GenericArgKind::Type(ty_a) => { - let ty_a = infcx.resolve_vars_if_possible(ty_a); + let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); let mut components = smallvec![]; push_outlives_components(tcx, ty_a, &mut components); implied_bounds_from_components(r_b, components) From 4e9ceef76d9daa33ebc936d46b955d00751fd21d Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 13 Nov 2022 13:02:52 +0100 Subject: [PATCH 05/38] Refactor `must_use` lint into two parts Before, the lint did the checking for `must_use` and pretty printing the types in a special format in one pass, causing quite complex and untranslatable code. Now the collection and printing is split in two. That should also make it easier to translate or extract the type pretty printing in the future. Also fixes an integer overflow in the array length pluralization calculation. --- compiler/rustc_lint/src/unused.rs | 316 +++++++++++------- src/test/ui/lint/unused/must-use-ops.rs | 20 +- src/test/ui/lint/unused/must-use-ops.stderr | 42 +-- src/test/ui/lint/unused/must_use-array.rs | 7 + src/test/ui/lint/unused/must_use-array.stderr | 20 +- 5 files changed, 259 insertions(+), 146 deletions(-) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index cdf279313a672..5c4c46f84d717 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{self, DefIdTree, Ty}; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; +use std::iter; declare_lint! { /// The `unused_must_use` lint detects unused result of a type flagged as @@ -113,30 +114,19 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } let ty = cx.typeck_results().expr_ty(&expr); - let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, expr.span, "", "", 1); - let mut fn_warned = false; - let mut op_warned = false; - let maybe_def_id = match expr.kind { - hir::ExprKind::Call(ref callee, _) => { - match callee.kind { - hir::ExprKind::Path(ref qpath) => { - match cx.qpath_res(qpath, callee.hir_id) { - Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id), - // `Res::Local` if it was a closure, for which we - // do not currently support must-use linting - _ => None, - } - } - _ => None, - } + let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span); + let type_lint_emitted_or_suppressed = match must_use_result { + Some(path) => { + emit_must_use_untranslated(cx, &path, "", "", 1); + true } - hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id), - _ => None, + None => false, }; - if let Some(def_id) = maybe_def_id { - fn_warned = check_must_use_def(cx, def_id, expr.span, "return value of ", ""); - } else if type_permits_lack_of_use { + + let fn_warned = check_fn_must_use(cx, expr); + + if !fn_warned && type_lint_emitted_or_suppressed { // We don't warn about unused unit or uninhabited types. // (See https://github.com/rust-lang/rust/issues/43806 for details.) return; @@ -170,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { _ => None, }; + let mut op_warned = false; + if let Some(must_use_op) = must_use_op { cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint_unused_op, |lint| { lint.set_arg("op", must_use_op) @@ -184,22 +176,64 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { op_warned = true; } - if !(type_permits_lack_of_use || fn_warned || op_warned) { + if !(type_lint_emitted_or_suppressed || fn_warned || op_warned) { cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint_unused_result, |lint| { lint.set_arg("ty", ty) }); } - // Returns whether an error has been emitted (and thus another does not need to be later). - fn check_must_use_ty<'tcx>( + fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + let maybe_def_id = match expr.kind { + hir::ExprKind::Call(ref callee, _) => { + match callee.kind { + hir::ExprKind::Path(ref qpath) => { + match cx.qpath_res(qpath, callee.hir_id) { + Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id), + // `Res::Local` if it was a closure, for which we + // do not currently support must-use linting + _ => None, + } + } + _ => None, + } + } + hir::ExprKind::MethodCall(..) => { + cx.typeck_results().type_dependent_def_id(expr.hir_id) + } + _ => None, + }; + if let Some(def_id) = maybe_def_id { + check_must_use_def(cx, def_id, expr.span, "return value of ", "") + } else { + false + } + } + + /// A path through a type to a must_use source. Contains useful info for the lint. + #[derive(Debug)] + enum MustUsePath { + /// Suppress must_use checking. + Suppressed, + /// The root of the normal must_use lint with an optional message. + Def(Span, DefId, Option<Symbol>), + Boxed(Box<Self>), + Opaque(Box<Self>), + TraitObject(Box<Self>), + TupleElement(Vec<(usize, Self)>), + Array(Box<Self>, u64), + /// The root of the unused_closures lint. + Closure(Span), + /// The root of the unused_generators lint. + Generator(Span), + } + + #[instrument(skip(cx, expr), level = "debug", ret)] + fn is_ty_must_use<'tcx>( cx: &LateContext<'tcx>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, span: Span, - descr_pre: &str, - descr_post: &str, - plural_len: usize, - ) -> bool { + ) -> Option<MustUsePath> { if ty.is_unit() || cx.tcx.is_ty_uninhabited_from( cx.tcx.parent_module(expr.hir_id).to_def_id(), @@ -207,87 +241,164 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx.param_env, ) { - return true; + return Some(MustUsePath::Suppressed); } - let plural_suffix = pluralize!(plural_len); - match *ty.kind() { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); - let descr_pre = &format!("{}boxed ", descr_pre); - check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len) + is_ty_must_use(cx, boxed_ty, expr, span) + .map(|inner| MustUsePath::Boxed(Box::new(inner))) } - ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post), + ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Opaque(def, _) => { - let mut has_emitted = false; - for obligation in elaborate_predicates_with_span( + elaborate_predicates_with_span( cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned(), - ) { + ) + .filter_map(|obligation| { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Trait(ref poly_trait_predicate) = obligation.predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; - let descr_pre = - &format!("{}implementer{} of ", descr_pre, plural_suffix,); - if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { - has_emitted = true; - break; - } + + is_def_must_use(cx, def_id, span) + } else { + None } - } - has_emitted + }) + .map(|inner| MustUsePath::Opaque(Box::new(inner))) + .next() } - ty::Dynamic(binder, _, _) => { - let mut has_emitted = false; - for predicate in binder.iter() { + ty::Dynamic(binders, _, _) => binders + .iter() + .filter_map(|predicate| { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { let def_id = trait_ref.def_id; - let descr_post = - &format!(" trait object{}{}", plural_suffix, descr_post,); - if check_must_use_def(cx, def_id, span, descr_pre, descr_post) { - has_emitted = true; - break; - } + is_def_must_use(cx, def_id, span) + } else { + None } - } - has_emitted - } - ty::Tuple(ref tys) => { - let mut has_emitted = false; - let comps = if let hir::ExprKind::Tup(comps) = expr.kind { - debug_assert_eq!(comps.len(), tys.len()); - comps + .map(|inner| MustUsePath::TraitObject(Box::new(inner))) + }) + .next(), + ty::Tuple(tys) => { + let elem_exprs = if let hir::ExprKind::Tup(elem_exprs) = expr.kind { + debug_assert_eq!(elem_exprs.len(), tys.len()); + elem_exprs } else { &[] }; - for (i, ty) in tys.iter().enumerate() { - let descr_post = &format!(" in tuple element {}", i); - let e = comps.get(i).unwrap_or(expr); - let span = e.span; - if check_must_use_ty(cx, ty, e, span, descr_pre, descr_post, plural_len) { - has_emitted = true; - } + + // Default to `expr`. + let elem_exprs = elem_exprs.iter().chain(iter::repeat(expr)); + + let nested_must_use = tys + .iter() + .zip(elem_exprs) + .enumerate() + .filter_map(|(i, (ty, expr))| { + is_ty_must_use(cx, ty, expr, expr.span).map(|path| (i, path)) + }) + .collect::<Vec<_>>(); + + if !nested_must_use.is_empty() { + Some(MustUsePath::TupleElement(nested_must_use)) + } else { + None } - has_emitted } ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) { // If the array is empty we don't lint, to avoid false positives - Some(0) | None => false, + Some(0) | None => None, // If the array is definitely non-empty, we can do `#[must_use]` checking. - Some(n) => { - let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix,); - check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1) - } + Some(len) => is_ty_must_use(cx, ty, expr, span) + .map(|inner| MustUsePath::Array(Box::new(inner), len)), }, - ty::Closure(..) => { + ty::Closure(..) => Some(MustUsePath::Closure(span)), + ty::Generator(..) => Some(MustUsePath::Generator(span)), + _ => None, + } + } + + fn is_def_must_use(cx: &LateContext<'_>, def_id: DefId, span: Span) -> Option<MustUsePath> { + if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { + // check for #[must_use = "..."] + let reason = attr.value_str(); + Some(MustUsePath::Def(span, def_id, reason)) + } else { + None + } + } + + // Returns whether further errors should be suppressed because either a lint has been emitted or the type should be ignored. + fn check_must_use_def( + cx: &LateContext<'_>, + def_id: DefId, + span: Span, + descr_pre_path: &str, + descr_post_path: &str, + ) -> bool { + is_def_must_use(cx, def_id, span) + .map(|must_use_path| { + emit_must_use_untranslated( + cx, + &must_use_path, + descr_pre_path, + descr_post_path, + 1, + ) + }) + .is_some() + } + + #[instrument(skip(cx), level = "debug")] + fn emit_must_use_untranslated( + cx: &LateContext<'_>, + path: &MustUsePath, + descr_pre: &str, + descr_post: &str, + plural_len: usize, + ) { + let plural_suffix = pluralize!(plural_len); + + match path { + MustUsePath::Suppressed => {} + MustUsePath::Boxed(path) => { + let descr_pre = &format!("{}boxed ", descr_pre); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + } + MustUsePath::Opaque(path) => { + let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + } + MustUsePath::TraitObject(path) => { + let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + } + MustUsePath::TupleElement(elems) => { + for (index, path) in elems { + let descr_post = &format!(" in tuple element {}", index); + emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len); + } + } + MustUsePath::Array(path, len) => { + let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)), + ); + } + MustUsePath::Closure(span) => { cx.struct_span_lint( UNUSED_MUST_USE, - span, + *span, fluent::lint_unused_closure, |lint| { // FIXME(davidtwco): this isn't properly translatable because of the @@ -298,12 +409,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .note(fluent::note) }, ); - true } - ty::Generator(..) => { + MustUsePath::Generator(span) => { cx.struct_span_lint( UNUSED_MUST_USE, - span, + *span, fluent::lint_unused_generator, |lint| { // FIXME(davidtwco): this isn't properly translatable because of the @@ -314,40 +424,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .note(fluent::note) }, ); - true } - _ => false, - } - } - - // Returns whether an error has been emitted (and thus another does not need to be later). - // FIXME: Args desc_{pre,post}_path could be made lazy by taking Fn() -> &str, but this - // would make calling it a big awkward. Could also take String (so args are moved), but - // this would still require a copy into the format string, which would only be executed - // when needed. - fn check_must_use_def( - cx: &LateContext<'_>, - def_id: DefId, - span: Span, - descr_pre_path: &str, - descr_post_path: &str, - ) -> bool { - if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { - cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint_unused_def, |lint| { - // FIXME(davidtwco): this isn't properly translatable because of the pre/post - // strings - lint.set_arg("pre", descr_pre_path); - lint.set_arg("post", descr_post_path); - lint.set_arg("def", cx.tcx.def_path_str(def_id)); - // check for #[must_use = "..."] - if let Some(note) = attr.value_str() { - lint.note(note.as_str()); - } - lint - }); - true - } else { - false + MustUsePath::Def(span, def_id, reason) => { + cx.struct_span_lint(UNUSED_MUST_USE, *span, fluent::lint_unused_def, |lint| { + // FIXME(davidtwco): this isn't properly translatable because of the pre/post + // strings + lint.set_arg("pre", descr_pre); + lint.set_arg("post", descr_post); + lint.set_arg("def", cx.tcx.def_path_str(*def_id)); + if let Some(note) = reason { + lint.note(note.as_str()); + } + lint + }); + } } } } diff --git a/src/test/ui/lint/unused/must-use-ops.rs b/src/test/ui/lint/unused/must-use-ops.rs index 3e425727e7829..60f877aa8b303 100644 --- a/src/test/ui/lint/unused/must-use-ops.rs +++ b/src/test/ui/lint/unused/must-use-ops.rs @@ -3,12 +3,18 @@ // check-pass #![warn(unused_must_use)] +#![feature(never_type)] + +fn deref_never(x: &!) { + // Don't lint for uninhabited typess + *x; +} fn main() { let val = 1; let val_pointer = &val; -// Comparison Operators + // Comparison Operators val == 1; //~ WARNING unused comparison val < 1; //~ WARNING unused comparison val <= 1; //~ WARNING unused comparison @@ -16,26 +22,30 @@ fn main() { val >= 1; //~ WARNING unused comparison val > 1; //~ WARNING unused comparison -// Arithmetic Operators + // Arithmetic Operators val + 2; //~ WARNING unused arithmetic operation val - 2; //~ WARNING unused arithmetic operation val / 2; //~ WARNING unused arithmetic operation val * 2; //~ WARNING unused arithmetic operation val % 2; //~ WARNING unused arithmetic operation -// Logical Operators + // Logical Operators true && true; //~ WARNING unused logical operation false || true; //~ WARNING unused logical operation -// Bitwise Operators + // Bitwise Operators 5 ^ val; //~ WARNING unused bitwise operation 5 & val; //~ WARNING unused bitwise operation 5 | val; //~ WARNING unused bitwise operation 5 << val; //~ WARNING unused bitwise operation 5 >> val; //~ WARNING unused bitwise operation -// Unary Operators + // Unary Operators !val; //~ WARNING unused unary operation -val; //~ WARNING unused unary operation *val_pointer; //~ WARNING unused unary operation + + if false { + deref_never(&panic!()); + } } diff --git a/src/test/ui/lint/unused/must-use-ops.stderr b/src/test/ui/lint/unused/must-use-ops.stderr index b248dd0fe1547..79a53d39cbf10 100644 --- a/src/test/ui/lint/unused/must-use-ops.stderr +++ b/src/test/ui/lint/unused/must-use-ops.stderr @@ -1,5 +1,5 @@ warning: unused comparison that must be used - --> $DIR/must-use-ops.rs:12:5 + --> $DIR/must-use-ops.rs:18:5 | LL | val == 1; | ^^^^^^^^ the comparison produces a value @@ -15,7 +15,7 @@ LL | let _ = val == 1; | +++++++ warning: unused comparison that must be used - --> $DIR/must-use-ops.rs:13:5 + --> $DIR/must-use-ops.rs:19:5 | LL | val < 1; | ^^^^^^^ the comparison produces a value @@ -26,7 +26,7 @@ LL | let _ = val < 1; | +++++++ warning: unused comparison that must be used - --> $DIR/must-use-ops.rs:14:5 + --> $DIR/must-use-ops.rs:20:5 | LL | val <= 1; | ^^^^^^^^ the comparison produces a value @@ -37,7 +37,7 @@ LL | let _ = val <= 1; | +++++++ warning: unused comparison that must be used - --> $DIR/must-use-ops.rs:15:5 + --> $DIR/must-use-ops.rs:21:5 | LL | val != 1; | ^^^^^^^^ the comparison produces a value @@ -48,7 +48,7 @@ LL | let _ = val != 1; | +++++++ warning: unused comparison that must be used - --> $DIR/must-use-ops.rs:16:5 + --> $DIR/must-use-ops.rs:22:5 | LL | val >= 1; | ^^^^^^^^ the comparison produces a value @@ -59,7 +59,7 @@ LL | let _ = val >= 1; | +++++++ warning: unused comparison that must be used - --> $DIR/must-use-ops.rs:17:5 + --> $DIR/must-use-ops.rs:23:5 | LL | val > 1; | ^^^^^^^ the comparison produces a value @@ -70,7 +70,7 @@ LL | let _ = val > 1; | +++++++ warning: unused arithmetic operation that must be used - --> $DIR/must-use-ops.rs:20:5 + --> $DIR/must-use-ops.rs:26:5 | LL | val + 2; | ^^^^^^^ the arithmetic operation produces a value @@ -81,7 +81,7 @@ LL | let _ = val + 2; | +++++++ warning: unused arithmetic operation that must be used - --> $DIR/must-use-ops.rs:21:5 + --> $DIR/must-use-ops.rs:27:5 | LL | val - 2; | ^^^^^^^ the arithmetic operation produces a value @@ -92,7 +92,7 @@ LL | let _ = val - 2; | +++++++ warning: unused arithmetic operation that must be used - --> $DIR/must-use-ops.rs:22:5 + --> $DIR/must-use-ops.rs:28:5 | LL | val / 2; | ^^^^^^^ the arithmetic operation produces a value @@ -103,7 +103,7 @@ LL | let _ = val / 2; | +++++++ warning: unused arithmetic operation that must be used - --> $DIR/must-use-ops.rs:23:5 + --> $DIR/must-use-ops.rs:29:5 | LL | val * 2; | ^^^^^^^ the arithmetic operation produces a value @@ -114,7 +114,7 @@ LL | let _ = val * 2; | +++++++ warning: unused arithmetic operation that must be used - --> $DIR/must-use-ops.rs:24:5 + --> $DIR/must-use-ops.rs:30:5 | LL | val % 2; | ^^^^^^^ the arithmetic operation produces a value @@ -125,7 +125,7 @@ LL | let _ = val % 2; | +++++++ warning: unused logical operation that must be used - --> $DIR/must-use-ops.rs:27:5 + --> $DIR/must-use-ops.rs:33:5 | LL | true && true; | ^^^^^^^^^^^^ the logical operation produces a value @@ -136,7 +136,7 @@ LL | let _ = true && true; | +++++++ warning: unused logical operation that must be used - --> $DIR/must-use-ops.rs:28:5 + --> $DIR/must-use-ops.rs:34:5 | LL | false || true; | ^^^^^^^^^^^^^ the logical operation produces a value @@ -147,7 +147,7 @@ LL | let _ = false || true; | +++++++ warning: unused bitwise operation that must be used - --> $DIR/must-use-ops.rs:31:5 + --> $DIR/must-use-ops.rs:37:5 | LL | 5 ^ val; | ^^^^^^^ the bitwise operation produces a value @@ -158,7 +158,7 @@ LL | let _ = 5 ^ val; | +++++++ warning: unused bitwise operation that must be used - --> $DIR/must-use-ops.rs:32:5 + --> $DIR/must-use-ops.rs:38:5 | LL | 5 & val; | ^^^^^^^ the bitwise operation produces a value @@ -169,7 +169,7 @@ LL | let _ = 5 & val; | +++++++ warning: unused bitwise operation that must be used - --> $DIR/must-use-ops.rs:33:5 + --> $DIR/must-use-ops.rs:39:5 | LL | 5 | val; | ^^^^^^^ the bitwise operation produces a value @@ -180,7 +180,7 @@ LL | let _ = 5 | val; | +++++++ warning: unused bitwise operation that must be used - --> $DIR/must-use-ops.rs:34:5 + --> $DIR/must-use-ops.rs:40:5 | LL | 5 << val; | ^^^^^^^^ the bitwise operation produces a value @@ -191,7 +191,7 @@ LL | let _ = 5 << val; | +++++++ warning: unused bitwise operation that must be used - --> $DIR/must-use-ops.rs:35:5 + --> $DIR/must-use-ops.rs:41:5 | LL | 5 >> val; | ^^^^^^^^ the bitwise operation produces a value @@ -202,7 +202,7 @@ LL | let _ = 5 >> val; | +++++++ warning: unused unary operation that must be used - --> $DIR/must-use-ops.rs:38:5 + --> $DIR/must-use-ops.rs:44:5 | LL | !val; | ^^^^ the unary operation produces a value @@ -213,7 +213,7 @@ LL | let _ = !val; | +++++++ warning: unused unary operation that must be used - --> $DIR/must-use-ops.rs:39:5 + --> $DIR/must-use-ops.rs:45:5 | LL | -val; | ^^^^ the unary operation produces a value @@ -224,7 +224,7 @@ LL | let _ = -val; | +++++++ warning: unused unary operation that must be used - --> $DIR/must-use-ops.rs:40:5 + --> $DIR/must-use-ops.rs:46:5 | LL | *val_pointer; | ^^^^^^^^^^^^ the unary operation produces a value diff --git a/src/test/ui/lint/unused/must_use-array.rs b/src/test/ui/lint/unused/must_use-array.rs index 97825dd2f6c43..b7bae4b0acf12 100644 --- a/src/test/ui/lint/unused/must_use-array.rs +++ b/src/test/ui/lint/unused/must_use-array.rs @@ -1,6 +1,7 @@ #![deny(unused_must_use)] #[must_use] +#[derive(Clone, Copy)] struct S; struct A; @@ -34,6 +35,10 @@ fn array_of_arrays_of_arrays() -> [[[S; 1]; 2]; 1] { [[[S], [S]]] } +fn usize_max() -> [S; usize::MAX] { + [S; usize::MAX] +} + fn main() { empty(); // ok singleton(); //~ ERROR unused array of `S` that must be used @@ -44,4 +49,6 @@ fn main() { //~^ ERROR unused array of boxed `T` trait objects in tuple element 1 that must be used array_of_arrays_of_arrays(); //~^ ERROR unused array of arrays of arrays of `S` that must be used + usize_max(); + //~^ ERROR unused array of `S` that must be used } diff --git a/src/test/ui/lint/unused/must_use-array.stderr b/src/test/ui/lint/unused/must_use-array.stderr index bba2b1ba078c6..61ef2088d30e5 100644 --- a/src/test/ui/lint/unused/must_use-array.stderr +++ b/src/test/ui/lint/unused/must_use-array.stderr @@ -1,5 +1,5 @@ error: unused array of `S` that must be used - --> $DIR/must_use-array.rs:39:5 + --> $DIR/must_use-array.rs:44:5 | LL | singleton(); | ^^^^^^^^^^^ @@ -11,34 +11,40 @@ LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ error: unused array of `S` that must be used - --> $DIR/must_use-array.rs:40:5 + --> $DIR/must_use-array.rs:45:5 | LL | many(); | ^^^^^^ error: unused array of `S` in tuple element 0 that must be used - --> $DIR/must_use-array.rs:41:6 + --> $DIR/must_use-array.rs:46:6 | LL | ([S], 0, ()); | ^^^ error: unused array of implementers of `T` that must be used - --> $DIR/must_use-array.rs:42:5 + --> $DIR/must_use-array.rs:47:5 | LL | array_of_impl_trait(); | ^^^^^^^^^^^^^^^^^^^^^ error: unused array of boxed `T` trait objects in tuple element 1 that must be used - --> $DIR/must_use-array.rs:43:5 + --> $DIR/must_use-array.rs:48:5 | LL | impl_array(); | ^^^^^^^^^^^^ error: unused array of arrays of arrays of `S` that must be used - --> $DIR/must_use-array.rs:45:5 + --> $DIR/must_use-array.rs:50:5 | LL | array_of_arrays_of_arrays(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: unused array of `S` that must be used + --> $DIR/must_use-array.rs:52:5 + | +LL | usize_max(); + | ^^^^^^^^^^^ + +error: aborting due to 7 previous errors From 644a5a34dd2f8ccd1c7423ba45931c5afefcdbf2 Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Sun, 20 Nov 2022 19:07:50 +0100 Subject: [PATCH 06/38] enable fuzzy_provenance_casts lint in liballoc --- library/alloc/benches/lib.rs | 2 ++ library/alloc/src/lib.rs | 1 + library/alloc/tests/fmt.rs | 13 +++++++------ library/alloc/tests/lib.rs | 1 + 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs index d418965cd2f6b..b25d63d835b54 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloc/benches/lib.rs @@ -5,7 +5,9 @@ #![feature(iter_next_chunk)] #![feature(repr_simd)] #![feature(slice_partition_dedup)] +#![feature(strict_provenance)] #![feature(test)] +#![deny(fuzzy_provenance_casts)] extern crate test; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 008926666c136..a9f2873faf97e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -82,6 +82,7 @@ // // Lints: #![deny(unsafe_op_in_unsafe_fn)] +#![deny(fuzzy_provenance_casts)] #![warn(deprecated_in_future)] #![warn(missing_debug_implementations)] #![warn(missing_docs)] diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs index 5ee6db43fda24..04da95bbb83ed 100644 --- a/library/alloc/tests/fmt.rs +++ b/library/alloc/tests/fmt.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::fmt::{self, Write}; +use std::ptr; #[test] fn test_format() { @@ -76,14 +77,14 @@ fn test_format_macro_interface() { t!(format!("{}", "foo"), "foo"); t!(format!("{}", "foo".to_string()), "foo"); if cfg!(target_pointer_width = "32") { - t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234"); - t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234"); + t!(format!("{:#p}", ptr::invalid::<isize>(0x1234)), "0x00001234"); + t!(format!("{:#p}", ptr::invalid_mut::<isize>(0x1234)), "0x00001234"); } else { - t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234"); - t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234"); + t!(format!("{:#p}", ptr::invalid::<isize>(0x1234)), "0x0000000000001234"); + t!(format!("{:#p}", ptr::invalid_mut::<isize>(0x1234)), "0x0000000000001234"); } - t!(format!("{:p}", 0x1234 as *const isize), "0x1234"); - t!(format!("{:p}", 0x1234 as *mut isize), "0x1234"); + t!(format!("{:p}", ptr::invalid::<isize>(0x1234)), "0x1234"); + t!(format!("{:p}", ptr::invalid_mut::<isize>(0x1234)), "0x1234"); t!(format!("{A:x}"), "aloha"); t!(format!("{B:X}"), "adios"); t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index ffc5ca7a5c6cc..d066ec03ee57e 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -47,6 +47,7 @@ #![feature(strict_provenance)] #![feature(once_cell)] #![feature(drain_keep_rest)] +#![deny(fuzzy_provenance_casts)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; From 7f5adddb2528be322c02cea44137d4192db3b8d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Sun, 20 Nov 2022 19:10:50 +0100 Subject: [PATCH 07/38] enable fuzzy_provenance_casts lint in libstd --- library/std/src/lib.rs | 3 ++- library/std/src/os/windows/io/socket.rs | 1 + library/std/src/personality/dwarf/eh.rs | 7 ++++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9334c833bb650..3eecfa806b564 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -220,6 +220,7 @@ #![allow(explicit_outlives_requirements)] #![allow(unused_lifetimes)] #![deny(rustc::existing_doc_keyword)] +#![deny(fuzzy_provenance_casts)] // Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` #![deny(ffi_unwind_calls)] // std may use features in a platform-specific way @@ -597,7 +598,7 @@ mod panicking; mod personality; #[path = "../../backtrace/src/lib.rs"] -#[allow(dead_code, unused_attributes)] +#[allow(dead_code, unused_attributes, fuzzy_provenance_casts)] mod backtrace_rs; // Re-export macros defined in libcore. diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 72cb3406dcada..5c1634084a055 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -90,6 +90,7 @@ impl OwnedSocket { } // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-; + #[allow(fuzzy_provenance_casts)] #[cfg(not(target_vendor = "uwp"))] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { cvt(unsafe { diff --git a/library/std/src/personality/dwarf/eh.rs b/library/std/src/personality/dwarf/eh.rs index 27b50c13b77ca..a783e187004fc 100644 --- a/library/std/src/personality/dwarf/eh.rs +++ b/library/std/src/personality/dwarf/eh.rs @@ -13,6 +13,7 @@ use super::DwarfReader; use core::mem; +use core::ptr; pub const DW_EH_PE_omit: u8 = 0xFF; pub const DW_EH_PE_absptr: u8 = 0x00; @@ -151,7 +152,7 @@ unsafe fn read_encoded_pointer( // DW_EH_PE_aligned implies it's an absolute pointer value if encoding == DW_EH_PE_aligned { - reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>())? as *const u8; + reader.ptr = reader.ptr.with_addr(round_up(reader.ptr.addr(), mem::size_of::<usize>())?); return Ok(reader.read::<usize>()); } @@ -171,7 +172,7 @@ unsafe fn read_encoded_pointer( result += match encoding & 0x70 { DW_EH_PE_absptr => 0, // relative to address of the encoded value, despite the name - DW_EH_PE_pcrel => reader.ptr as usize, + DW_EH_PE_pcrel => reader.ptr.expose_addr(), DW_EH_PE_funcrel => { if context.func_start == 0 { return Err(()); @@ -184,7 +185,7 @@ unsafe fn read_encoded_pointer( }; if encoding & DW_EH_PE_indirect != 0 { - result = *(result as *const usize); + result = *ptr::from_exposed_addr::<usize>(result); } Ok(result) From 1a6966602a06bb85d1952027e990d72f6d01792f Mon Sep 17 00:00:00 2001 From: Ralf Jung <post@ralfj.de> Date: Mon, 21 Nov 2022 16:10:56 +0100 Subject: [PATCH 08/38] dont attempt strict provenance in SGX --- library/std/src/sys/sgx/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index b1d32929ecfde..01e4ffe3dfc8a 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -3,6 +3,7 @@ //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Fortanix SGX. #![deny(unsafe_op_in_unsafe_fn)] +#![allow(fuzzy_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers use crate::io::ErrorKind; use crate::sync::atomic::{AtomicBool, Ordering}; From 2752e328c9696aa3f8f61046507392ecdedc6667 Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 24 Oct 2022 15:31:38 +0000 Subject: [PATCH 09/38] Allow opaque types in trait impl headers and rely on coherence to reject unsound cases --- .../src/coherence/orphan.rs | 53 ------------------- compiler/rustc_middle/src/ty/fast_reject.rs | 18 ++----- .../src/traits/coherence.rs | 6 +-- .../ui/coherence/coherence-with-closure.rs | 1 - .../coherence/coherence-with-closure.stderr | 17 +----- .../ui/coherence/coherence-with-generator.rs | 1 - .../coherence/coherence-with-generator.stderr | 17 +----- src/test/ui/impl-trait/auto-trait.rs | 1 - src/test/ui/impl-trait/auto-trait.stderr | 14 +---- src/test/ui/impl-trait/negative-reasoning.rs | 1 - .../ui/impl-trait/negative-reasoning.stderr | 14 +---- ...ias-impl-trait-declaration-too-subtle-2.rs | 2 +- ...impl-trait-declaration-too-subtle-2.stderr | 19 +++---- ...alias-impl-trait-declaration-too-subtle.rs | 5 +- ...s-impl-trait-declaration-too-subtle.stderr | 49 ++++++++++++++--- src/test/ui/traits/alias/issue-83613.rs | 1 - src/test/ui/traits/alias/issue-83613.stderr | 14 +---- .../ui/type-alias-impl-trait/coherence.rs | 2 +- .../ui/type-alias-impl-trait/coherence.stderr | 16 +++--- .../impl_trait_for_generic_tait.rs | 23 ++++++++ .../impl_trait_for_tait.rs | 21 ++++++++ .../impl_trait_for_tait_bound.rs | 19 +++++++ .../impl_trait_for_tait_bound.stderr | 16 ++++++ .../impl_trait_for_tait_bound2.rs | 16 ++++++ .../impl_trait_for_tait_bound2.stderr | 16 ++++++ .../ui/type-alias-impl-trait/issue-65384.rs | 2 +- .../type-alias-impl-trait/issue-65384.stderr | 16 +++--- .../issue-76202-trait-impl-for-tait.rs | 9 +++- .../issue-76202-trait-impl-for-tait.stderr | 14 ----- .../issue-84660-trait-impl-for-tait.rs | 4 +- .../issue-84660-trait-impl-for-tait.stderr | 14 ----- .../issue-84660-unsoundness.rs | 4 +- .../issue-84660-unsoundness.stderr | 16 +++--- .../nested-tait-inference3.rs | 2 +- .../nested-tait-inference3.stderr | 10 ++-- 35 files changed, 224 insertions(+), 229 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr delete mode 100644 src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr delete mode 100644 src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 71c932d747bca..d66b6585fb6f7 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{struct_span_err, DelayDm}; use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IgnoreRegions; use rustc_middle::ty::{ @@ -47,58 +46,6 @@ fn do_orphan_check_impl<'tcx>( let sp = tcx.def_span(def_id); let tr = impl_.of_trait.as_ref().unwrap(); - // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples, - // and #84660 where it would otherwise allow unsoundness. - if trait_ref.has_opaque_types() { - trace!("{:#?}", item); - // First we find the opaque type in question. - for ty in trait_ref.substs { - for ty in ty.walk() { - let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue }; - let ty::Opaque(def_id, _) = *ty.kind() else { continue }; - trace!(?def_id); - - // Then we search for mentions of the opaque type's type alias in the HIR - struct SpanFinder<'tcx> { - sp: Span, - def_id: DefId, - tcx: TyCtxt<'tcx>, - } - impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> { - #[instrument(level = "trace", skip(self, _id))] - fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) { - // You can't mention an opaque type directly, so we look for type aliases - if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res { - // And check if that type alias's type contains the opaque type we're looking for - for arg in self.tcx.type_of(def_id).walk() { - if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Opaque(def_id, _) = *ty.kind() { - if def_id == self.def_id { - // Finally we update the span to the mention of the type alias - self.sp = path.span; - return; - } - } - } - } - } - hir::intravisit::walk_path(self, path) - } - } - - let mut visitor = SpanFinder { sp, def_id, tcx }; - hir::intravisit::walk_item(&mut visitor, item); - let reported = tcx - .sess - .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait") - .span_note(tcx.def_span(def_id), "type alias impl trait defined here") - .emit(); - return Err(reported); - } - } - span_bug!(sp, "opaque type not found, but `has_opaque_types` is set") - } - match traits::orphan_check(tcx, item.owner_id.to_def_id()) { Ok(()) => {} Err(err) => emit_orphan_check_error( diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 3be0bc4defc5c..1ee4985cf8de0 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -42,7 +42,6 @@ where ClosureSimplifiedType(D), GeneratorSimplifiedType(D), GeneratorWitnessSimplifiedType(usize), - OpaqueSimplifiedType(D), FunctionSimplifiedType(usize), PlaceholderSimplifiedType, } @@ -127,7 +126,7 @@ pub fn simplify_type<'tcx>( TreatParams::AsPlaceholder => Some(PlaceholderSimplifiedType), TreatParams::AsInfer => None, }, - ty::Projection(_) => match treat_params { + ty::Opaque(..) | ty::Projection(_) => match treat_params { // When treating `ty::Param` as a placeholder, projections also // don't unify with anything else as long as they are fully normalized. // @@ -138,7 +137,6 @@ pub fn simplify_type<'tcx>( } TreatParams::AsPlaceholder | TreatParams::AsInfer => None, }, - ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)), ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, } @@ -151,8 +149,7 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> { | ForeignSimplifiedType(d) | TraitSimplifiedType(d) | ClosureSimplifiedType(d) - | GeneratorSimplifiedType(d) - | OpaqueSimplifiedType(d) => Some(d), + | GeneratorSimplifiedType(d) => Some(d), _ => None, } } @@ -182,7 +179,6 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> { ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)), GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)), GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n), - OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)), FunctionSimplifiedType(n) => FunctionSimplifiedType(n), PlaceholderSimplifiedType => PlaceholderSimplifiedType, } @@ -229,7 +225,7 @@ impl DeepRejectCtxt { match impl_ty.kind() { // Start by checking whether the type in the impl may unify with // pretty much everything. Just return `true` in that case. - ty::Param(_) | ty::Projection(_) | ty::Error(_) => return true, + ty::Param(_) | ty::Projection(_) | ty::Error(_) | ty::Opaque(..) => return true, // These types only unify with inference variables or their own // variant. ty::Bool @@ -247,8 +243,7 @@ impl DeepRejectCtxt { | ty::Never | ty::Tuple(..) | ty::FnPtr(..) - | ty::Foreign(..) - | ty::Opaque(..) => {} + | ty::Foreign(..) => {} ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) @@ -328,10 +323,7 @@ impl DeepRejectCtxt { _ => false, }, - // Opaque types in impls should be forbidden, but that doesn't - // stop compilation. So this match arm should never return true - // if compilation succeeds. - ty::Opaque(..) => matches!(k, ty::Opaque(..)), + ty::Opaque(..) => true, // Impls cannot contain these types as these cannot be named directly. ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 3cf2959a9ffc5..ff013b761e379 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::CRATE_HIR_ID; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -94,7 +94,7 @@ pub fn overlapping_impls<'tcx>( return None; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); let selcx = &mut SelectionContext::intercrate(&infcx); let overlaps = overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); @@ -105,7 +105,7 @@ pub fn overlapping_impls<'tcx>( // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); let selcx = &mut SelectionContext::intercrate(&infcx); selcx.enable_tracking_intercrate_ambiguity_causes(); Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) diff --git a/src/test/ui/coherence/coherence-with-closure.rs b/src/test/ui/coherence/coherence-with-closure.rs index 6e3281d8508ab..5b6a62b24d4b3 100644 --- a/src/test/ui/coherence/coherence-with-closure.rs +++ b/src/test/ui/coherence/coherence-with-closure.rs @@ -8,7 +8,6 @@ fn defining_use() -> OpaqueClosure { struct Wrapper<T>(T); trait Trait {} impl Trait for Wrapper<OpaqueClosure> {} -//~^ ERROR cannot implement trait on type alias impl trait impl<T: Sync> Trait for Wrapper<T> {} //~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>` diff --git a/src/test/ui/coherence/coherence-with-closure.stderr b/src/test/ui/coherence/coherence-with-closure.stderr index d2ca63fa14691..431108e14d7d8 100644 --- a/src/test/ui/coherence/coherence-with-closure.stderr +++ b/src/test/ui/coherence/coherence-with-closure.stderr @@ -1,24 +1,11 @@ error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueClosure>` - --> $DIR/coherence-with-closure.rs:12:1 + --> $DIR/coherence-with-closure.rs:11:1 | LL | impl Trait for Wrapper<OpaqueClosure> {} | ------------------------------------- first implementation here -LL | LL | impl<T: Sync> Trait for Wrapper<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueClosure>` -error: cannot implement trait on type alias impl trait - --> $DIR/coherence-with-closure.rs:10:24 - | -LL | impl Trait for Wrapper<OpaqueClosure> {} - | ^^^^^^^^^^^^^ - | -note: type alias impl trait defined here - --> $DIR/coherence-with-closure.rs:3:22 - | -LL | type OpaqueClosure = impl Sized; - | ^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-with-generator.rs b/src/test/ui/coherence/coherence-with-generator.rs index d34c391db9fb0..70665ba06f954 100644 --- a/src/test/ui/coherence/coherence-with-generator.rs +++ b/src/test/ui/coherence/coherence-with-generator.rs @@ -12,7 +12,6 @@ fn defining_use() -> OpaqueGenerator { struct Wrapper<T>(T); trait Trait {} impl Trait for Wrapper<OpaqueGenerator> {} -//~^ ERROR cannot implement trait on type alias impl trait impl<T: Sync> Trait for Wrapper<T> {} //~^ ERROR conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>` diff --git a/src/test/ui/coherence/coherence-with-generator.stderr b/src/test/ui/coherence/coherence-with-generator.stderr index 804bc1c3a6dd4..6d3be2e16c657 100644 --- a/src/test/ui/coherence/coherence-with-generator.stderr +++ b/src/test/ui/coherence/coherence-with-generator.stderr @@ -1,24 +1,11 @@ error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueGenerator>` - --> $DIR/coherence-with-generator.rs:16:1 + --> $DIR/coherence-with-generator.rs:15:1 | LL | impl Trait for Wrapper<OpaqueGenerator> {} | --------------------------------------- first implementation here -LL | LL | impl<T: Sync> Trait for Wrapper<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Wrapper<OpaqueGenerator>` -error: cannot implement trait on type alias impl trait - --> $DIR/coherence-with-generator.rs:14:24 - | -LL | impl Trait for Wrapper<OpaqueGenerator> {} - | ^^^^^^^^^^^^^^^ - | -note: type alias impl trait defined here - --> $DIR/coherence-with-generator.rs:3:24 - | -LL | type OpaqueGenerator = impl Sized; - | ^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs index afa95645a2786..35994e4a5ba3f 100644 --- a/src/test/ui/impl-trait/auto-trait.rs +++ b/src/test/ui/impl-trait/auto-trait.rs @@ -20,7 +20,6 @@ impl<T: Send> AnotherTrait for T {} // in the future.) impl AnotherTrait for D<OpaqueType> { //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` - //~| ERROR cannot implement trait on type alias impl trait } fn main() {} diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr index 5e10272b0db3c..81009413c9a26 100644 --- a/src/test/ui/impl-trait/auto-trait.stderr +++ b/src/test/ui/impl-trait/auto-trait.stderr @@ -7,18 +7,6 @@ LL | impl<T: Send> AnotherTrait for T {} LL | impl AnotherTrait for D<OpaqueType> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` -error: cannot implement trait on type alias impl trait - --> $DIR/auto-trait.rs:21:25 - | -LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^ - | -note: type alias impl trait defined here - --> $DIR/auto-trait.rs:7:19 - | -LL | type OpaqueType = impl OpaqueTrait; - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs index da69bb349ae24..70e24a3a9d029 100644 --- a/src/test/ui/impl-trait/negative-reasoning.rs +++ b/src/test/ui/impl-trait/negative-reasoning.rs @@ -18,7 +18,6 @@ impl<T: std::fmt::Debug> AnotherTrait for T {} // This is in error, because we cannot assume that `OpaqueType: !Debug` impl AnotherTrait for D<OpaqueType> { //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` - //~| ERROR cannot implement trait on type alias impl trait } fn main() {} diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr index 479b451855d55..6b8cc9e737423 100644 --- a/src/test/ui/impl-trait/negative-reasoning.stderr +++ b/src/test/ui/impl-trait/negative-reasoning.stderr @@ -9,18 +9,6 @@ LL | impl AnotherTrait for D<OpaqueType> { | = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions -error: cannot implement trait on type alias impl trait - --> $DIR/negative-reasoning.rs:19:25 - | -LL | impl AnotherTrait for D<OpaqueType> { - | ^^^^^^^^^^ - | -note: type alias impl trait defined here - --> $DIR/negative-reasoning.rs:7:19 - | -LL | type OpaqueType = impl OpaqueTrait; - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs index 621c4ea6e0d48..af9dfe25bb4ce 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs @@ -5,13 +5,13 @@ type Foo = impl PartialEq<(Foo, i32)>; struct Bar; impl PartialEq<(Foo, i32)> for Bar { -//~^ ERROR cannot implement trait on type alias impl trait fn eq(&self, _other: &(Foo, i32)) -> bool { true } } fn foo() -> Foo { + //~^ ERROR can't compare `Bar` with `(Bar, i32)` Bar } diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr index 2ef1697ba341d..7b63a3d0b9f10 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr @@ -1,14 +1,15 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:7:17 +error[E0277]: can't compare `Bar` with `(Bar, i32)` + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:13:13 | -LL | impl PartialEq<(Foo, i32)> for Bar { - | ^^^ +LL | fn foo() -> Foo { + | ^^^ no implementation for `Bar == (Bar, i32)` +LL | +LL | Bar + | --- return type was inferred to be `Bar` here | -note: type alias impl trait defined here - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:3:12 - | -LL | type Foo = impl PartialEq<(Foo, i32)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar` + = help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar` error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs index df7966f00e172..91f1ed48133f5 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs @@ -2,11 +2,13 @@ mod a { type Foo = impl PartialEq<(Foo, i32)>; + //~^ ERROR: unconstrained opaque type struct Bar; impl PartialEq<(Bar, i32)> for Bar { fn eq(&self, _other: &(Foo, i32)) -> bool { + //~^ ERROR: `eq` has an incompatible type for trait true } } @@ -14,12 +16,13 @@ mod a { mod b { type Foo = impl PartialEq<(Foo, i32)>; + //~^ ERROR: unconstrained opaque type struct Bar; impl PartialEq<(Foo, i32)> for Bar { - //~^ ERROR cannot implement trait on type alias impl trait fn eq(&self, _other: &(Bar, i32)) -> bool { + //~^ ERROR: `eq` has an incompatible type for trait true } } diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index 6cd63dcf81c7f..3dda5761ada6b 100644 --- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -1,14 +1,49 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:20:21 +error: unconstrained opaque type + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16 | -LL | impl PartialEq<(Foo, i32)> for Bar { - | ^^^ +LL | type Foo = impl PartialEq<(Foo, i32)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same module + +error[E0053]: method `eq` has an incompatible type for trait + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:10:30 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | -------------------------- the found opaque type +... +LL | fn eq(&self, _other: &(Foo, i32)) -> bool { + | ^^^^^^^^^^^ + | | + | expected struct `a::Bar`, found opaque type + | help: change the parameter type to match the trait: `&(a::Bar, i32)` | -note: type alias impl trait defined here - --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:16:16 + = note: expected fn pointer `fn(&a::Bar, &(a::Bar, i32)) -> _` + found fn pointer `fn(&a::Bar, &(a::Foo, i32)) -> _` + +error: unconstrained opaque type + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:18:16 | LL | type Foo = impl PartialEq<(Foo, i32)>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `Foo` must be used in combination with a concrete type within the same module + +error[E0053]: method `eq` has an incompatible type for trait + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:30 + | +LL | type Foo = impl PartialEq<(Foo, i32)>; + | -------------------------- the expected opaque type +... +LL | fn eq(&self, _other: &(Bar, i32)) -> bool { + | ^^^^^^^^^^^ + | | + | expected opaque type, found struct `b::Bar` + | help: change the parameter type to match the trait: `&(b::Foo, i32)` + | + = note: expected fn pointer `fn(&b::Bar, &(b::Foo, i32)) -> _` + found fn pointer `fn(&b::Bar, &(b::Bar, i32)) -> _` -error: aborting due to previous error +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0053`. diff --git a/src/test/ui/traits/alias/issue-83613.rs b/src/test/ui/traits/alias/issue-83613.rs index 04320e7207683..2462e703a7165 100644 --- a/src/test/ui/traits/alias/issue-83613.rs +++ b/src/test/ui/traits/alias/issue-83613.rs @@ -9,5 +9,4 @@ trait AnotherTrait {} impl<T: Send> AnotherTrait for T {} impl AnotherTrait for OpaqueType {} //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `OpaqueType` -//~| ERROR cannot implement trait on type alias impl trait fn main() {} diff --git a/src/test/ui/traits/alias/issue-83613.stderr b/src/test/ui/traits/alias/issue-83613.stderr index b9d93160192e9..a78294da6c140 100644 --- a/src/test/ui/traits/alias/issue-83613.stderr +++ b/src/test/ui/traits/alias/issue-83613.stderr @@ -6,18 +6,6 @@ LL | impl<T: Send> AnotherTrait for T {} LL | impl AnotherTrait for OpaqueType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `OpaqueType` -error: cannot implement trait on type alias impl trait - --> $DIR/issue-83613.rs:10:23 - | -LL | impl AnotherTrait for OpaqueType {} - | ^^^^^^^^^^ - | -note: type alias impl trait defined here - --> $DIR/issue-83613.rs:4:19 - | -LL | type OpaqueType = impl OpaqueTrait; - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/type-alias-impl-trait/coherence.rs b/src/test/ui/type-alias-impl-trait/coherence.rs index 98ac215ad6cc5..077a31494a972 100644 --- a/src/test/ui/type-alias-impl-trait/coherence.rs +++ b/src/test/ui/type-alias-impl-trait/coherence.rs @@ -12,6 +12,6 @@ fn use_alias<T>(val: T) -> AliasOfForeignType<T> { } impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {} -//~^ ERROR cannot implement trait on type alias impl trait +//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr index 3ce25d94f6e12..c923eb08ab312 100644 --- a/src/test/ui/type-alias-impl-trait/coherence.stderr +++ b/src/test/ui/type-alias-impl-trait/coherence.stderr @@ -1,14 +1,14 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/coherence.rs:14:41 +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/coherence.rs:14:1 | LL | impl<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------- + | | | + | | `AliasOfForeignType<T>` is not defined in the current crate + | impl doesn't use only types from inside the current crate | -note: type alias impl trait defined here - --> $DIR/coherence.rs:9:30 - | -LL | type AliasOfForeignType<T> = impl LocalTrait; - | ^^^^^^^^^^^^^^^ + = note: define and implement a trait or new type instead error: aborting due to previous error +For more information about this error, try `rustc --explain E0117`. diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs new file mode 100644 index 0000000000000..0efbd1c2bd5fd --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_generic_tait.rs @@ -0,0 +1,23 @@ +// check-pass + +#![feature(type_alias_impl_trait)] +trait Foo { + type Assoc; +} + +impl Foo for i32 { + type Assoc = u32; +} +type ImplTrait = impl Sized; +fn constrain() -> ImplTrait { + 1u64 +} +impl Foo for i64 { + type Assoc = ImplTrait; +} + +trait Bar<T> {} + +impl<T: Foo> Bar<<T as Foo>::Assoc> for T {} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs new file mode 100644 index 0000000000000..9f32c5d888b5f --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait.rs @@ -0,0 +1,21 @@ +// compile-flags: --crate-type=lib +// check-pass + +#![feature(type_alias_impl_trait)] +type Alias = impl Sized; + +fn constrain() -> Alias { + 1i32 +} + +trait HideIt { + type Assoc; +} + +impl HideIt for () { + type Assoc = Alias; +} + +pub trait Yay {} + +impl Yay for <() as HideIt>::Assoc {} diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs new file mode 100644 index 0000000000000..8ec20acef4de6 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.rs @@ -0,0 +1,19 @@ +#![feature(type_alias_impl_trait)] + +use std::fmt::Debug; + +type Foo = impl Debug; +pub trait Yay { } +impl Yay for Foo { } + +fn foo() { + is_yay::<u32>(); //~ ERROR: the trait bound `u32: Yay` is not satisfied + is_debug::<u32>(); // OK + is_yay::<Foo>(); // OK + is_debug::<Foo>(); // OK +} + +fn is_yay<T: Yay>() { } +fn is_debug<T: Debug>() { } + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr new file mode 100644 index 0000000000000..1c83105a18aff --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `u32: Yay` is not satisfied + --> $DIR/impl_trait_for_tait_bound.rs:10:14 + | +LL | is_yay::<u32>(); + | ^^^ the trait `Yay` is not implemented for `u32` + | + = help: the trait `Yay` is implemented for `Foo` +note: required by a bound in `is_yay` + --> $DIR/impl_trait_for_tait_bound.rs:16:14 + | +LL | fn is_yay<T: Yay>() { } + | ^^^ required by this bound in `is_yay` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs new file mode 100644 index 0000000000000..a4b8c2d190db9 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +use std::fmt::Debug; + +type Foo = impl Debug; + +pub trait Yay { } +impl Yay for u32 { } + +fn foo() { + is_yay::<Foo>(); //~ ERROR: the trait bound `Foo: Yay` is not satisfied +} + +fn is_yay<T: Yay>() { } + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr new file mode 100644 index 0000000000000..a6440f02c27d8 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_tait_bound2.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `Foo: Yay` is not satisfied + --> $DIR/impl_trait_for_tait_bound2.rs:11:14 + | +LL | is_yay::<Foo>(); + | ^^^ the trait `Yay` is not implemented for `Foo` + | + = help: the trait `Yay` is implemented for `u32` +note: required by a bound in `is_yay` + --> $DIR/impl_trait_for_tait_bound2.rs:14:14 + | +LL | fn is_yay<T: Yay>() { } + | ^^^ required by this bound in `is_yay` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-65384.rs b/src/test/ui/type-alias-impl-trait/issue-65384.rs index 9a119c4d2e0aa..9a9b2269f802e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-65384.rs +++ b/src/test/ui/type-alias-impl-trait/issue-65384.rs @@ -8,7 +8,7 @@ impl MyTrait for () {} type Bar = impl MyTrait; impl MyTrait for Bar {} -//~^ ERROR: cannot implement trait on type alias impl trait +//~^ ERROR: conflicting implementations of trait `MyTrait` for type `()` fn bazr() -> Bar { } diff --git a/src/test/ui/type-alias-impl-trait/issue-65384.stderr b/src/test/ui/type-alias-impl-trait/issue-65384.stderr index 41bcea27e1fa3..f6692ae320733 100644 --- a/src/test/ui/type-alias-impl-trait/issue-65384.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-65384.stderr @@ -1,14 +1,12 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/issue-65384.rs:10:18 +error[E0119]: conflicting implementations of trait `MyTrait` for type `()` + --> $DIR/issue-65384.rs:10:1 | +LL | impl MyTrait for () {} + | ------------------- first implementation here +... LL | impl MyTrait for Bar {} - | ^^^ - | -note: type alias impl trait defined here - --> $DIR/issue-65384.rs:8:12 - | -LL | type Bar = impl MyTrait; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` error: aborting due to previous error +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs index fb56cc54d634b..b97e444c6d0e0 100644 --- a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs +++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -1,6 +1,8 @@ // Regression test for issue #76202 // Tests that we don't ICE when we have a trait impl on a TAIT. +// check-pass + #![feature(type_alias_impl_trait)] trait Dummy {} @@ -14,7 +16,12 @@ trait Test { } impl Test for F { - //~^ ERROR cannot implement trait + fn test(self) {} +} + +// Ok because `i32` does not implement `Dummy`, +// so it can't possibly be the hidden type of `F`. +impl Test for i32 { fn test(self) {} } diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr deleted file mode 100644 index 2d4a6854a920b..0000000000000 --- a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/issue-76202-trait-impl-for-tait.rs:16:15 - | -LL | impl Test for F { - | ^ - | -note: type alias impl trait defined here - --> $DIR/issue-76202-trait-impl-for-tait.rs:9:10 - | -LL | type F = impl Dummy; - | ^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs index fa25d8f762e6c..2ba4befea2a39 100644 --- a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs +++ b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs @@ -1,6 +1,8 @@ // Regression test for issues #84660 and #86411: both are variations on #76202. // Tests that we don't ICE when we have an opaque type appearing anywhere in an impl header. +// check-pass + #![feature(type_alias_impl_trait)] trait Foo {} @@ -12,7 +14,7 @@ trait TraitArg<T> { fn f(); } -impl TraitArg<Bar> for () { //~ ERROR cannot implement trait +impl TraitArg<Bar> for () { fn f() { println!("ho"); } diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr deleted file mode 100644 index bb70d07be59bb..0000000000000 --- a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/issue-84660-trait-impl-for-tait.rs:15:15 - | -LL | impl TraitArg<Bar> for () { - | ^^^ - | -note: type alias impl trait defined here - --> $DIR/issue-84660-trait-impl-for-tait.rs:8:12 - | -LL | type Bar = impl Foo; - | ^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs index f12d1b6d953cd..48d4b0c96ff0a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs +++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs @@ -13,14 +13,14 @@ trait Trait<T, In> { fn convert(i: In) -> Self::Out; } -impl<In, Out> Trait<Bar, In> for Out { //~ ERROR cannot implement trait +impl<In, Out> Trait<Bar, In> for Out { type Out = Out; fn convert(_i: In) -> Self::Out { unreachable!(); } } -impl<In, Out> Trait<(), In> for Out { +impl<In, Out> Trait<(), In> for Out { //~ ERROR conflicting implementations of trait `Trait<Bar, _>` type Out = In; fn convert(i: In) -> Self::Out { i diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr index f2d600fb46c54..6a75e1bd2c0fa 100644 --- a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr @@ -1,14 +1,12 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/issue-84660-unsoundness.rs:16:21 +error[E0119]: conflicting implementations of trait `Trait<Bar, _>` + --> $DIR/issue-84660-unsoundness.rs:23:1 | LL | impl<In, Out> Trait<Bar, In> for Out { - | ^^^ - | -note: type alias impl trait defined here - --> $DIR/issue-84660-unsoundness.rs:8:12 - | -LL | type Bar = impl Foo; - | ^^^^^^^^ + | ------------------------------------ first implementation here +... +LL | impl<In, Out> Trait<(), In> for Out { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation error: aborting due to previous error +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs index ebf3a99bbf9f0..b0ebdd1bfab7d 100644 --- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs +++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs @@ -4,11 +4,11 @@ use std::fmt::Debug; type FooX = impl Debug; +//~^ ERROR unconstrained opaque type trait Foo<A> { } impl Foo<FooX> for () { } -//~^ cannot implement trait on type alias impl trait fn foo() -> impl Foo<FooX> { () diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr index 4a3fb16733e04..b1d947a9ccf4e 100644 --- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr +++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr @@ -1,14 +1,10 @@ -error: cannot implement trait on type alias impl trait - --> $DIR/nested-tait-inference3.rs:10:10 - | -LL | impl Foo<FooX> for () { } - | ^^^^ - | -note: type alias impl trait defined here +error: unconstrained opaque type --> $DIR/nested-tait-inference3.rs:6:13 | LL | type FooX = impl Debug; | ^^^^^^^^^^ + | + = note: `FooX` must be used in combination with a concrete type within the same module error: aborting due to previous error From 94fe30ff2fa39a912325121846074a659e8ec420 Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 27 Oct 2022 12:00:21 +0000 Subject: [PATCH 10/38] Treat different opaque types of the same def id as equal during coherence --- .../rustc_hir_analysis/src/check/dropck.rs | 4 ++ compiler/rustc_infer/src/infer/at.rs | 1 + compiler/rustc_infer/src/infer/combine.rs | 9 ++++ compiler/rustc_infer/src/infer/equate.rs | 4 ++ .../src/infer/error_reporting/mod.rs | 4 ++ compiler/rustc_infer/src/infer/glb.rs | 4 ++ compiler/rustc_infer/src/infer/lub.rs | 4 ++ compiler/rustc_infer/src/infer/mod.rs | 29 +++++++++++ .../rustc_infer/src/infer/nll_relate/mod.rs | 8 ++++ .../src/infer/outlives/test_type_match.rs | 5 ++ compiler/rustc_infer/src/infer/sub.rs | 5 ++ compiler/rustc_middle/src/ty/_match.rs | 5 ++ compiler/rustc_middle/src/ty/relate.rs | 28 +++++++---- .../src/traits/coherence.rs | 10 ++-- .../src/traits/select/mod.rs | 48 +++++-------------- .../impl_trait_for_same_tait.rs | 34 +++++++++++++ .../impl_trait_for_same_tait.stderr | 30 ++++++++++++ 17 files changed, 182 insertions(+), 50 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs create mode 100644 src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index a74016e220e62..923a55f705d6c 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -244,6 +244,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { self.tcx } + fn intercrate(&self) -> bool { + false + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 5ff3779fa1438..2483ab724a4e3 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -81,6 +81,7 @@ impl<'tcx> InferCtxt<'tcx> { .normalize_fn_sig_for_diagnostic .as_ref() .map(|f| f.clone()), + intercrate: self.intercrate, } } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index c2552561c42df..743e776d58c9e 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -521,6 +521,11 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } + + fn intercrate(&self) -> bool { + self.infcx.intercrate + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } @@ -799,6 +804,10 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { self.infcx.tcx } + fn intercrate(&self) -> bool { + self.infcx.intercrate + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 59728148a84c4..dca955778f866 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -32,6 +32,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.fields.tcx() } + fn intercrate(&self) -> bool { + self.fields.infcx.intercrate + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d773aa5f1fce1..8b14fe18fec44 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2937,6 +2937,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { self.0.tcx } + fn intercrate(&self) -> bool { + self.0.intercrate + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { // Unused, only for consts which we treat as always equal ty::ParamEnv::empty() diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 6ffefcb7a286a..16a80a1a5d63c 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -30,6 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { "Glb" } + fn intercrate(&self) -> bool { + self.fields.infcx.intercrate + } + fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index d6e56fcb7fd27..ef6b7ebfeea67 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -30,6 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { "Lub" } + fn intercrate(&self) -> bool { + self.fields.infcx.intercrate + } + fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b9ed6b28c220d..fd4ca9365f976 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -337,6 +337,26 @@ pub struct InferCtxt<'tcx> { normalize_fn_sig_for_diagnostic: Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, + + /// During coherence we have to assume that other crates may add + /// additional impls which we currently don't know about. + /// + /// To deal with this evaluation should be conservative + /// and consider the possibility of impls from outside this crate. + /// This comes up primarily when resolving ambiguity. Imagine + /// there is some trait reference `$0: Bar` where `$0` is an + /// inference variable. If `intercrate` is true, then we can never + /// say for sure that this reference is not implemented, even if + /// there are *no impls at all for `Bar`*, because `$0` could be + /// bound to some type that in a downstream crate that implements + /// `Bar`. + /// + /// Outside of coherence we set this to false because we are only + /// interested in types that the user could actually have written. + /// In other words, we consider `$0: Bar` to be unimplemented if + /// there is no type that the user could *actually name* that + /// would satisfy it. This avoids crippling inference, basically. + pub intercrate: bool, } /// See the `error_reporting` module for more details. @@ -554,6 +574,7 @@ pub struct InferCtxtBuilder<'tcx> { considering_regions: bool, normalize_fn_sig_for_diagnostic: Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, + intercrate: bool, } pub trait TyCtxtInferExt<'tcx> { @@ -567,6 +588,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { defining_use_anchor: DefiningAnchor::Error, considering_regions: true, normalize_fn_sig_for_diagnostic: None, + intercrate: false, } } } @@ -583,6 +605,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn intercrate(mut self) -> Self { + self.intercrate = true; + self + } + pub fn ignoring_regions(mut self) -> Self { self.considering_regions = false; self @@ -622,6 +649,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { defining_use_anchor, considering_regions, ref normalize_fn_sig_for_diagnostic, + intercrate, } = *self; InferCtxt { tcx, @@ -641,6 +669,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic .as_ref() .map(|f| f.clone()), + intercrate, } } } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 167a82d4499a1..6e846171d67db 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -531,6 +531,10 @@ where self.infcx.tcx } + fn intercrate(&self) -> bool { + self.infcx.intercrate + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.delegate.param_env() } @@ -898,6 +902,10 @@ where self.infcx.tcx } + fn intercrate(&self) -> bool { + self.infcx.intercrate + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.delegate.param_env() } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index a5c21f0fb9b50..198e6b1d4f225 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -136,6 +136,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { fn tag(&self) -> &'static str { "Match" } + + fn intercrate(&self) -> bool { + false + } + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index bd3c5780b891b..2faf7db5b136f 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -35,6 +35,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "Sub" } + + fn intercrate(&self) -> bool { + self.fields.infcx.intercrate + } + fn tcx(&self) -> TyCtxt<'tcx> { self.fields.infcx.tcx } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index e6aab30a150de..bcf2058b9f032 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -36,6 +36,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } + + fn intercrate(&self) -> bool { + false + } + fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 6d02551716e35..1a9b959fb845b 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -23,6 +23,8 @@ pub enum Cause { pub trait TypeRelation<'tcx>: Sized { fn tcx(&self) -> TyCtxt<'tcx>; + fn intercrate(&self) -> bool; + fn param_env(&self) -> ty::ParamEnv<'tcx>; /// Returns a static string we can use for printouts. @@ -562,16 +564,22 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs)) if a_def_id == b_def_id => { - let opt_variances = tcx.variances_of(a_def_id); - let substs = relate_substs_with_variances( - relation, - a_def_id, - opt_variances, - a_substs, - b_substs, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?; - Ok(tcx.mk_opaque(a_def_id, substs)) + if relation.intercrate() { + // During coherence, opaque types should be treated as equal to each other, even if their generic params + // differ, as they could resolve to the same hidden type, even for different generic params. + Ok(a) + } else { + let opt_variances = tcx.variances_of(a_def_id); + let substs = relate_substs_with_variances( + relation, + a_def_id, + opt_variances, + a_substs, + b_substs, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?; + Ok(tcx.mk_opaque(a_def_id, substs)) + } } _ => Err(TypeError::Sorts(expected_found(relation, a, b))), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ff013b761e379..8006af2a40f9f 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -94,8 +94,9 @@ pub fn overlapping_impls<'tcx>( return None; } - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); - let selcx = &mut SelectionContext::intercrate(&infcx); + let infcx = + tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let selcx = &mut SelectionContext::new(&infcx); let overlaps = overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); if !overlaps { @@ -105,8 +106,9 @@ pub fn overlapping_impls<'tcx>( // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build(); - let selcx = &mut SelectionContext::intercrate(&infcx); + let infcx = + tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let selcx = &mut SelectionContext::new(&infcx); selcx.enable_tracking_intercrate_ambiguity_causes(); Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a9314b1b85e66..87fcfdb33fc6c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -110,25 +110,6 @@ pub struct SelectionContext<'cx, 'tcx> { /// require themselves. freshener: TypeFreshener<'cx, 'tcx>, - /// During coherence we have to assume that other crates may add - /// additional impls which we currently don't know about. - /// - /// To deal with this evaluation should be conservative - /// and consider the possibility of impls from outside this crate. - /// This comes up primarily when resolving ambiguity. Imagine - /// there is some trait reference `$0: Bar` where `$0` is an - /// inference variable. If `intercrate` is true, then we can never - /// say for sure that this reference is not implemented, even if - /// there are *no impls at all for `Bar`*, because `$0` could be - /// bound to some type that in a downstream crate that implements - /// `Bar`. - /// - /// Outside of coherence we set this to false because we are only - /// interested in types that the user could actually have written. - /// In other words, we consider `$0: Bar` to be unimplemented if - /// there is no type that the user could *actually name* that - /// would satisfy it. This avoids crippling inference, basically. - intercrate: bool, /// If `intercrate` is set, we remember predicates which were /// considered ambiguous because of impls potentially added in other crates. /// This is used in coherence to give improved diagnostics. @@ -226,16 +207,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, freshener: infcx.freshener_keep_static(), - intercrate: false, intercrate_ambiguity_causes: None, query_mode: TraitQueryMode::Standard, } } - pub fn intercrate(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { intercrate: true, ..SelectionContext::new(infcx) } - } - pub fn with_query_mode( infcx: &'cx InferCtxt<'tcx>, query_mode: TraitQueryMode, @@ -247,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Enables tracking of intercrate ambiguity causes. See /// the documentation of [`Self::intercrate_ambiguity_causes`] for more. pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { - assert!(self.intercrate); + assert!(self.is_intercrate()); assert!(self.intercrate_ambiguity_causes.is_none()); self.intercrate_ambiguity_causes = Some(FxIndexSet::default()); debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); @@ -257,7 +233,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// was enabled and disables tracking at the same time. If /// tracking is not enabled, just returns an empty vector. pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> { - assert!(self.intercrate); + assert!(self.is_intercrate()); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -270,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } pub fn is_intercrate(&self) -> bool { - self.intercrate + self.infcx.intercrate } /////////////////////////////////////////////////////////////////////////// @@ -751,7 +727,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - if !self.intercrate + if !self.is_intercrate() && obligation.is_global() && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst()) { @@ -1014,7 +990,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // mode, so don't do any caching. In particular, we might // re-use the same `InferCtxt` with both an intercrate // and non-intercrate `SelectionContext` - if self.intercrate { + if self.is_intercrate() { return None; } @@ -1044,7 +1020,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // mode, so don't do any caching. In particular, we might // re-use the same `InferCtxt` with both an intercrate // and non-intercrate `SelectionContext` - if self.intercrate { + if self.is_intercrate() { return; } @@ -1225,9 +1201,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { - debug!("is_knowable(intercrate={:?})", self.intercrate); + debug!("is_knowable(intercrate={:?})", self.is_intercrate()); - if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative { + if !self.is_intercrate() || stack.obligation.polarity() == ty::ImplPolarity::Negative { return Ok(()); } @@ -1258,7 +1234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // the master cache. Since coherence executes pretty quickly, // it's not worth going to more trouble to increase the // hit-rate, I don't think. - if self.intercrate { + if self.is_intercrate() { return false; } @@ -1275,7 +1251,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // mode, so don't do any caching. In particular, we might // re-use the same `InferCtxt` with both an intercrate // and non-intercrate `SelectionContext` - if self.intercrate { + if self.is_intercrate() { return None; } let tcx = self.tcx(); @@ -1314,7 +1290,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // mode, so don't do any caching. In particular, we might // re-use the same `InferCtxt` with both an intercrate // and non-intercrate `SelectionContext` - if self.intercrate { + if self.is_intercrate() { return false; } match result { @@ -2192,7 +2168,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?; nested_obligations.extend(obligations); - if !self.intercrate + if !self.is_intercrate() && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation { debug!("reservation impls only apply in intercrate mode"); diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs new file mode 100644 index 0000000000000..d942a268a7a1b --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs @@ -0,0 +1,34 @@ +#![feature(type_alias_impl_trait)] + +trait Foo {} +impl Foo for () {} +impl Foo for i32 {} + +type Bar<T: Foo> = impl std::fmt::Debug; +fn defining_use<T: Foo>() -> Bar<T> { + 42 +} + +trait Bop {} + +impl Bop for Bar<()> {} + +// If the hidden type is the same, this is effectively a second impl for the same type. +impl Bop for Bar<i32> {} +//~^ ERROR conflicting implementations + +type Barr = impl std::fmt::Debug; +fn defining_use2() -> Barr { + 42 +} + +// Even completely different opaque types must conflict. +impl Bop for Barr {} +//~^ ERROR conflicting implementations + +// And obviously the hidden type must conflict, too. +impl Bop for i32 {} +//~^ ERROR conflicting implementations + +fn main() { +} diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr new file mode 100644 index 0000000000000..aaf75cc3db97c --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr @@ -0,0 +1,30 @@ +error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>` + --> $DIR/impl_trait_for_same_tait.rs:17:1 + | +LL | impl Bop for Bar<()> {} + | -------------------- first implementation here +... +LL | impl Bop for Bar<i32> {} + | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>` + +error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>` + --> $DIR/impl_trait_for_same_tait.rs:26:1 + | +LL | impl Bop for Bar<()> {} + | -------------------- first implementation here +... +LL | impl Bop for Barr {} + | ^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>` + +error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>` + --> $DIR/impl_trait_for_same_tait.rs:30:1 + | +LL | impl Bop for Bar<()> {} + | -------------------- first implementation here +... +LL | impl Bop for i32 {} + | ^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0119`. From ae80c764d46a3c250a6cc41e5d2de5b8ed48567e Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Wed, 2 Nov 2022 15:10:05 +0000 Subject: [PATCH 11/38] Add an always-ambiguous predicate to make sure that we don't accidentlally allow trait resolution to prove false things during coherence --- .../src/type_check/relate_tys.rs | 7 +------ .../rustc_hir_analysis/src/check/dropck.rs | 4 ++++ .../src/impl_wf_check/min_specialization.rs | 1 + .../src/outlives/explicit.rs | 1 + compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 1 + compiler/rustc_hir_typeck/src/method/probe.rs | 1 + .../src/infer/canonical/query_response.rs | 7 +------ compiler/rustc_infer/src/infer/combine.rs | 18 ++++++++++++++++++ compiler/rustc_infer/src/infer/equate.rs | 4 ++++ .../src/infer/error_reporting/mod.rs | 4 ++++ compiler/rustc_infer/src/infer/glb.rs | 4 ++++ compiler/rustc_infer/src/infer/lub.rs | 4 ++++ .../rustc_infer/src/infer/nll_relate/mod.rs | 15 ++++++++++----- compiler/rustc_infer/src/infer/outlives/mod.rs | 1 + .../src/infer/outlives/test_type_match.rs | 4 ++++ compiler/rustc_infer/src/infer/sub.rs | 4 ++++ compiler/rustc_infer/src/traits/util.rs | 1 + compiler/rustc_lint/src/builtin.rs | 1 + compiler/rustc_middle/src/ty/_match.rs | 4 ++++ compiler/rustc_middle/src/ty/flags.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 8 ++++++++ compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_middle/src/ty/relate.rs | 4 ++++ .../rustc_middle/src/ty/structural_impls.rs | 1 + .../src/traits/auto_trait.rs | 1 + .../src/traits/error_reporting/mod.rs | 2 ++ .../src/traits/fulfill.rs | 2 ++ .../src/traits/object_safety.rs | 2 ++ .../src/traits/select/mod.rs | 1 + .../rustc_trait_selection/src/traits/wf.rs | 2 ++ compiler/rustc_traits/src/chalk/lowering.rs | 4 ++++ .../src/implied_outlives_bounds.rs | 1 + .../src/normalize_erasing_regions.rs | 1 + src/librustdoc/clean/mod.rs | 1 + .../clippy_utils/src/qualify_min_const_fn.rs | 1 + 35 files changed, 102 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 94d5103286609..45c6405d03ad6 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -2,7 +2,6 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRe use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Const, Ty}; use rustc_span::Span; @@ -156,10 +155,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> true } - fn register_opaque_type_obligations( - &mut self, - obligations: PredicateObligations<'tcx>, - ) -> Result<(), TypeError<'tcx>> { + fn register_opaque_type_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.type_checker .fully_perform_op( self.locations, @@ -172,6 +168,5 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> }, ) .unwrap(); - Ok(()) } } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 923a55f705d6c..e0b465bab16d9 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -260,6 +260,10 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { true } + fn mark_ambiguous(&mut self) { + bug!() + } + fn relate_with_variance<T: Relate<'tcx>>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 55cca0cd2d7b5..bae43138b4d52 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -517,6 +517,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } } diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 7534482cce9bb..f0381353551c2 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -59,6 +59,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => (), } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index b85a23257286b..efce33bfe4724 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -702,6 +702,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // code is looking for a self type of an unresolved // inference variable. | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, }, ) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 9d75ccad133dd..44c3edf06a883 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -803,6 +803,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } }); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 34f54328230f4..fb86fad84583d 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -23,7 +23,6 @@ use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; @@ -741,11 +740,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { true } - fn register_opaque_type_obligations( - &mut self, - obligations: PredicateObligations<'tcx>, - ) -> Result<(), TypeError<'tcx>> { + fn register_opaque_type_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.obligations.extend(obligations); - Ok(()) } } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 743e776d58c9e..53a19f8e4ec55 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -450,6 +450,15 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { ty::Binder::dummy(predicate), )); } + + pub fn mark_ambiguous(&mut self) { + self.obligations.push(Obligation::new( + self.tcx(), + self.trace.cause.clone(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Ambiguous), + )); + } } struct Generalizer<'cx, 'tcx> { @@ -538,6 +547,11 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { true } + fn mark_ambiguous(&mut self) { + // The generalizer always compares types against themselves, + // and thus doesn't really take part in coherence. + } + fn binders<T>( &mut self, a: ty::Binder<'tcx, T>, @@ -820,6 +834,10 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { true } + fn mark_ambiguous(&mut self) { + bug!() + } + fn relate_with_variance<T: Relate<'tcx>>( &mut self, _variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index dca955778f866..8682f4d3b7aed 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -44,6 +44,10 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { self.a_is_expected } + fn mark_ambiguous(&mut self) { + self.fields.mark_ambiguous(); + } + fn relate_item_substs( &mut self, _item_def_id: DefId, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8b14fe18fec44..41e21efb212bb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2954,6 +2954,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { true } + fn mark_ambiguous(&mut self) { + bug!() + } + fn relate_with_variance<T: relate::Relate<'tcx>>( &mut self, _variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 16a80a1a5d63c..67f3e67e96322 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -46,6 +46,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { self.a_is_expected } + fn mark_ambiguous(&mut self) { + self.fields.mark_ambiguous(); + } + fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index ef6b7ebfeea67..1aaae714345c1 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -46,6 +46,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { self.a_is_expected } + fn mark_ambiguous(&mut self) { + self.fields.mark_ambiguous(); + } + fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 6e846171d67db..be7b0bc60329d 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -93,10 +93,7 @@ pub trait TypeRelatingDelegate<'tcx> { ); fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); - fn register_opaque_type_obligations( - &mut self, - obligations: Vec<PredicateObligation<'tcx>>, - ) -> Result<(), TypeError<'tcx>>; + fn register_opaque_type_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>); /// Creates a new universe index. Used when instantiating placeholders. fn create_next_universe(&mut self) -> ty::UniverseIndex; @@ -419,7 +416,7 @@ where .infcx .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())? .obligations; - self.delegate.register_opaque_type_obligations(obligations)?; + self.delegate.register_opaque_type_obligations(obligations); trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); Ok(a) } @@ -547,6 +544,10 @@ where true } + fn mark_ambiguous(&mut self) { + bug!() + } + #[instrument(skip(self, info), level = "trace", ret)] fn relate_with_variance<T: Relate<'tcx>>( &mut self, @@ -918,6 +919,10 @@ where true } + fn mark_ambiguous(&mut self) { + bug!() + } + fn relate_with_variance<T: Relate<'tcx>>( &mut self, variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 2d19d1823fdfc..8f7805794513d 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -29,6 +29,7 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { Some(OutlivesBound::RegionSubRegion(r_b, r_a)) diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 198e6b1d4f225..5d204dd70ed0c 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -151,6 +151,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { true } // irrelevant + fn mark_ambiguous(&mut self) { + bug!() + } + fn relate_with_variance<T: Relate<'tcx>>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 2faf7db5b136f..2c6987cc3f456 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -52,6 +52,10 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { self.a_is_expected } + fn mark_ambiguous(&mut self) { + self.fields.mark_ambiguous() + } + fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index e12c069dcc1d9..b2a31ac7e6f1a 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -285,6 +285,7 @@ impl<'tcx> Elaborator<'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { // Nothing to elaborate } + ty::PredicateKind::Ambiguous => {} } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c2d0a662ddbcd..01a5ba65d8fcd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1659,6 +1659,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { Coerce(..) | ConstEvaluatable(..) | ConstEquate(..) | + Ambiguous | TypeWellFormedFromEnv(..) => continue, }; if predicate.is_global() { diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index bcf2058b9f032..cd147d7e55813 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -48,6 +48,10 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { true } // irrelevant + fn mark_ambiguous(&mut self) { + bug!() + } + fn relate_with_variance<T: Relate<'tcx>>( &mut self, _: ty::Variance, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 7201737be657b..ee4b8f91c5487 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -259,6 +259,7 @@ impl FlagComputation { ty::PredicateKind::TypeWellFormedFromEnv(ty) => { self.add_ty(ty); } + ty::PredicateKind::Ambiguous => {} } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ffb4ad4db88f5..a4dddc17b6ff1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -619,6 +619,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(_) | PredicateKind::ConstEvaluatable(_) | PredicateKind::ConstEquate(_, _) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(_) => true, } } @@ -701,6 +702,10 @@ pub enum PredicateKind<'tcx> { /// /// Only used for Chalk. TypeWellFormedFromEnv(Ty<'tcx>), + + /// A marker predicate that is always ambiguous. + /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. + Ambiguous, } /// The crate outlives map is computed during typeck and contains the @@ -1181,6 +1186,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -1199,6 +1205,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -1217,6 +1224,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) | PredicateKind::ConstEquate(..) + | PredicateKind::Ambiguous | PredicateKind::TypeWellFormedFromEnv(..) => None, } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 023c9d26c42e3..4db4d57e26f8d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2703,6 +2703,7 @@ define_print_and_forward_display! { ty::PredicateKind::TypeWellFormedFromEnv(ty) => { p!("the type `", print(ty), "` is found in the environment") } + ty::PredicateKind::Ambiguous => p!("ambiguous"), } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 1a9b959fb845b..3461ae870e4af 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -34,6 +34,9 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; + /// Used during coherence. If called, must emit an always-ambiguous obligation. + fn mark_ambiguous(&mut self); + fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -567,6 +570,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( if relation.intercrate() { // During coherence, opaque types should be treated as equal to each other, even if their generic params // differ, as they could resolve to the same hidden type, even for different generic params. + relation.mark_ambiguous(); Ok(a) } else { let opt_variances = tcx.variances_of(a_def_id); diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 9f0598d0ba86b..18da620b29857 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -173,6 +173,7 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(ty) => { write!(f, "TypeWellFormedFromEnv({:?})", ty) } + ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"), } } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 5869bc76b596c..0cd6ed88f0082 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -843,6 +843,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} + ty::PredicateKind::Ambiguous => return false, }; } true 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 c3547f64b5c9c..e4734d3d982e2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1176,6 +1176,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } + ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"), + ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!( span, "TypeWellFormedFromEnv predicate should only exist in the environment" diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d84f768cce4d7..d238e7556aea3 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -336,6 +336,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)])) } + ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } @@ -569,6 +570,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } + ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 9745e0137ee9f..db6f59ceebe0a 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -319,6 +319,7 @@ fn predicate_references_self<'tcx>( | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } } @@ -350,6 +351,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, } }) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 87fcfdb33fc6c..ab9a0d57a4de1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -717,6 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for chalk") } + ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), } }) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d05e893de433a..38bd3bc4322f5 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -155,6 +155,7 @@ pub fn predicate_obligations<'tcx>( wf.compute(c1.into()); wf.compute(c2.into()); } + ty::PredicateKind::Ambiguous => {} ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } @@ -878,6 +879,7 @@ pub(crate) fn required_region_bounds<'tcx>( | ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { // Search for a bound of the form `erased_self_ty diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 25cedefa26127..3e8bb9e575b32 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -121,6 +121,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate), }; let value = chalk_ir::ProgramClauseImplication { @@ -212,6 +213,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } @@ -625,6 +627,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("unexpected predicate {}", &self) } @@ -754,6 +757,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("unexpected predicate {}", &self) } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 82f6111f6f92e..2d1a386992617 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -97,6 +97,7 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::WellFormed(arg) => { wf_args.push(arg); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index f1835d317e841..5200908527a16 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -66,6 +66,7 @@ fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => true, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c20595614b0b9..a49c631035b6d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -318,6 +318,7 @@ pub(crate) fn clean_predicate<'tcx>( | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"), } } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 45b63a4aa5df8..b48bacb9ace6f 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -37,6 +37,7 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"), ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"), ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"), + ty::PredicateKind::Ambiguous => panic!("ambiguous predicate on function: {predicate:#?}"), } } match predicates.parent { From 9cd44f81427a0536a9dceeb56e5801ad53d285b5 Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Nov 2022 17:22:50 +0000 Subject: [PATCH 12/38] nit treat different opaque types --- src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs index d942a268a7a1b..3f1a9d12b44f9 100644 --- a/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs +++ b/src/test/ui/type-alias-impl-trait/impl_trait_for_same_tait.rs @@ -30,5 +30,4 @@ impl Bop for Barr {} impl Bop for i32 {} //~^ ERROR conflicting implementations -fn main() { -} +fn main() {} From 9a8e1eea7a8c86d493c96c2010247ce6126c6a10 Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Nov 2022 17:35:40 +0000 Subject: [PATCH 13/38] Move a field around --- compiler/rustc_infer/src/infer/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index fd4ca9365f976..2798477d1815d 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -572,9 +572,10 @@ pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, defining_use_anchor: DefiningAnchor, considering_regions: bool, + /// Whether we are in coherence mode. + intercrate: bool, normalize_fn_sig_for_diagnostic: Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, - intercrate: bool, } pub trait TyCtxtInferExt<'tcx> { From f42e490d6f57e4a346211daab9c188cf130f532b Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Mon, 14 Nov 2022 17:48:27 +0000 Subject: [PATCH 14/38] Register obligations from type relation --- .../rustc_borrowck/src/type_check/relate_tys.rs | 2 +- .../src/infer/canonical/query_response.rs | 2 +- compiler/rustc_infer/src/infer/nll_relate/mod.rs | 15 +++++++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 45c6405d03ad6..2353ccc0c0582 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -155,7 +155,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> true } - fn register_opaque_type_obligations(&mut self, obligations: PredicateObligations<'tcx>) { + fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.type_checker .fully_perform_op( self.locations, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index fb86fad84583d..6972656db76c3 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -740,7 +740,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { true } - fn register_opaque_type_obligations(&mut self, obligations: PredicateObligations<'tcx>) { + fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.obligations.extend(obligations); } } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index be7b0bc60329d..62ec7f57bfb14 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -25,7 +25,7 @@ use crate::infer::combine::ConstEquateRelation; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::traits::PredicateObligation; +use crate::traits::{Obligation, PredicateObligation}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; @@ -93,7 +93,7 @@ pub trait TypeRelatingDelegate<'tcx> { ); fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); - fn register_opaque_type_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>); + fn register_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>); /// Creates a new universe index. Used when instantiating placeholders. fn create_next_universe(&mut self) -> ty::UniverseIndex; @@ -416,7 +416,7 @@ where .infcx .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())? .obligations; - self.delegate.register_opaque_type_obligations(obligations); + self.delegate.register_obligations(obligations); trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); Ok(a) } @@ -545,7 +545,14 @@ where } fn mark_ambiguous(&mut self) { - bug!() + let cause = ObligationCause::dummy_with_span(self.delegate.span()); + let param_env = self.delegate.param_env(); + self.delegate.register_obligations(vec![Obligation::new( + self.tcx(), + cause, + param_env, + ty::Binder::dummy(ty::PredicateKind::Ambiguous), + )]); } #[instrument(skip(self, info), level = "trace", ret)] From 11ae334f076ae488566a9814d145a727fa89a6dc Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Tue, 15 Nov 2022 12:37:05 +0000 Subject: [PATCH 15/38] Remove a function that doesn't actually do anything --- compiler/rustc_borrowck/src/type_check/relate_tys.rs | 9 +-------- .../rustc_infer/src/infer/canonical/query_response.rs | 6 +----- compiler/rustc_infer/src/infer/nll_relate/mod.rs | 9 ++++++--- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 2353ccc0c0582..b2702eafd33bd 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -3,7 +3,7 @@ use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::traits::PredicateObligations; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, Const, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use rustc_trait_selection::traits::query::Fallible; @@ -140,13 +140,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> ); } - // We don't have to worry about the equality of consts during borrow checking - // as consts always have a static lifetime. - // FIXME(oli-obk): is this really true? We can at least have HKL and with - // inline consts we may have further lifetimes that may be unsound to treat as - // 'static. - fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {} - fn normalization() -> NormalizationStrategy { NormalizationStrategy::Eager } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 6972656db76c3..b4a427a5d419a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -26,7 +26,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, BoundVar, ToPredicate, Ty, TyCtxt}; use rustc_span::Span; use std::fmt::Debug; use std::iter; @@ -728,10 +728,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { }); } - fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) { - span_bug!(self.cause.span(), "generic_const_exprs: unreachable `const_equate`"); - } - fn normalization() -> NormalizationStrategy { NormalizationStrategy::Eager } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 62ec7f57bfb14..0687774078015 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -92,7 +92,6 @@ pub trait TypeRelatingDelegate<'tcx> { info: ty::VarianceDiagInfo<'tcx>, ); - fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); fn register_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>); /// Creates a new universe index. Used when instantiating placeholders. @@ -812,8 +811,12 @@ impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, { - fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { - self.delegate.const_equate(a, b); + fn const_equate_obligation(&mut self, _a: ty::Const<'tcx>, _b: ty::Const<'tcx>) { + // We don't have to worry about the equality of consts during borrow checking + // as consts always have a static lifetime. + // FIXME(oli-obk): is this really true? We can at least have HKL and with + // inline consts we may have further lifetimes that may be unsound to treat as + // 'static. } } From 7301cd784437d289a34604a3c4145ed1801c902d Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 17 Nov 2022 09:49:18 +0000 Subject: [PATCH 16/38] Type generalization should not look at opaque type in coherence --- compiler/rustc_infer/src/infer/combine.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 53a19f8e4ec55..f8234df871b26 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -548,8 +548,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } fn mark_ambiguous(&mut self) { - // The generalizer always compares types against themselves, - // and thus doesn't really take part in coherence. + self.infcx.tcx.sess.delay_span_bug(self.cause.span, "opaque types are handled in `tys`"); } fn binders<T>( From 11adf037906fd918e0a77116db8c8b17e0fcee73 Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 17 Nov 2022 09:58:22 +0000 Subject: [PATCH 17/38] Add some more assertions for type relations not used during coherence --- compiler/rustc_infer/src/infer/combine.rs | 5 +++-- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 3 ++- compiler/rustc_infer/src/infer/glb.rs | 5 +++-- compiler/rustc_infer/src/infer/lub.rs | 5 +++-- compiler/rustc_infer/src/infer/nll_relate/mod.rs | 3 ++- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index f8234df871b26..256a6dc47f40c 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -548,7 +548,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } fn mark_ambiguous(&mut self) { - self.infcx.tcx.sess.delay_span_bug(self.cause.span, "opaque types are handled in `tys`"); + self.infcx.tcx.sess.delay_span_bug(self.cause.span, "we only generalize opaque types in situations where we already error for them elsewhere in coherence"); } fn binders<T>( @@ -818,7 +818,8 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } fn intercrate(&self) -> bool { - self.infcx.intercrate + assert!(!self.infcx.intercrate); + false } fn param_env(&self) -> ty::ParamEnv<'tcx> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 41e21efb212bb..da5d4ebf4171d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2938,7 +2938,8 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { } fn intercrate(&self) -> bool { - self.0.intercrate + assert!(!self.0.intercrate); + false } fn param_env(&self) -> ty::ParamEnv<'tcx> { diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 67f3e67e96322..7f27b35a54e4f 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -31,7 +31,8 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { } fn intercrate(&self) -> bool { - self.fields.infcx.intercrate + assert!(!self.fields.infcx.intercrate); + false } fn tcx(&self) -> TyCtxt<'tcx> { @@ -47,7 +48,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { } fn mark_ambiguous(&mut self) { - self.fields.mark_ambiguous(); + bug!("mark_ambiguous used outside of coherence"); } fn relate_with_variance<T: Relate<'tcx>>( diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 1aaae714345c1..97ed4729bd0d9 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -31,7 +31,8 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { } fn intercrate(&self) -> bool { - self.fields.infcx.intercrate + assert!(!self.fields.infcx.intercrate); + false } fn tcx(&self) -> TyCtxt<'tcx> { @@ -47,7 +48,7 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { } fn mark_ambiguous(&mut self) { - self.fields.mark_ambiguous(); + bug!("mark_ambiguous used outside of coherence"); } fn relate_with_variance<T: Relate<'tcx>>( diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 0687774078015..4f8460955c3de 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -914,7 +914,8 @@ where } fn intercrate(&self) -> bool { - self.infcx.intercrate + assert!(!self.infcx.intercrate); + false } fn param_env(&self) -> ty::ParamEnv<'tcx> { From c16a90f5e3cb26b15e12c8d24d7b1cafbe90e24a Mon Sep 17 00:00:00 2001 From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> Date: Thu, 17 Nov 2022 10:40:35 +0000 Subject: [PATCH 18/38] Test generalization during coherence --- compiler/rustc_infer/src/infer/combine.rs | 6 +++++- .../coherence_generalization.rs | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/type-alias-impl-trait/coherence_generalization.rs diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 256a6dc47f40c..eec938cefbb70 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -548,7 +548,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } fn mark_ambiguous(&mut self) { - self.infcx.tcx.sess.delay_span_bug(self.cause.span, "we only generalize opaque types in situations where we already error for them elsewhere in coherence"); + span_bug!(self.cause.span, "opaque types are handled in `tys`"); } fn binders<T>( @@ -675,6 +675,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // relatable. Ok(t) } + ty::Opaque(def_id, substs) => { + let s = self.relate(substs, substs)?; + Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) }) + } _ => relate::super_relate_tys(self, t, t), }?; diff --git a/src/test/ui/type-alias-impl-trait/coherence_generalization.rs b/src/test/ui/type-alias-impl-trait/coherence_generalization.rs new file mode 100644 index 0000000000000..5c9ad9498b6de --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/coherence_generalization.rs @@ -0,0 +1,13 @@ +// check-pass + +#![feature(type_alias_impl_trait)] +trait Trait {} +type Opaque<T> = impl Sized; +fn foo<T>() -> Opaque<T> { + () +} + +impl<T, V> Trait for (T, V, V, u32) {} +impl<U, V> Trait for (Opaque<U>, V, i32, V) {} + +fn main() {} From 98cb7c8373fdcdfd65bc0e389832faa14ebf95e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Wed, 2 Nov 2022 21:22:24 -0700 Subject: [PATCH 19/38] Suggest `.clone()` or `ref binding` on E0382 --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/mut_visit.rs | 3 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 4 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 192 ++++++++++++++++-- .../src/assert/context.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 5 +- compiler/rustc_resolve/src/late.rs | 4 +- .../binding/issue-53114-borrow-checks.stderr | 16 ++ src/test/ui/binop/binop-move-semantics.stderr | 4 + ...atterns-slice-patterns-box-patterns.stderr | 23 +++ .../borrowck-consume-unsize-vec.stderr | 12 ++ .../borrowck-consume-upcast-box.stderr | 8 + .../borrowck/borrowck-drop-from-guard.stderr | 5 + .../borrowck-loan-in-overloaded-op.stderr | 5 + .../borrowck-move-out-from-array-match.stderr | 40 ++++ ...ove-out-from-array-no-overlap-match.stderr | 36 ++++ ...rowck-move-out-from-array-use-match.stderr | 56 +++++ ...out-from-array-use-no-overlap-match.stderr | 36 ++++ .../borrowck-move-out-from-array-use.stderr | 56 +++++ .../borrowck-move-out-from-array.stderr | 40 ++++ .../borrowck-multiple-captures.stderr | 15 ++ ...orrowck-overloaded-index-move-index.stderr | 5 + src/test/ui/borrowck/borrowck-reinit.stderr | 5 + .../borrowck/issue-31287-drop-in-guard.stderr | 5 + src/test/ui/borrowck/issue-41962.stderr | 2 +- src/test/ui/borrowck/issue-83760.stderr | 4 + .../move-in-pattern-mut-in-loop.stderr | 2 +- .../ui/borrowck/move-in-pattern-mut.stderr | 4 +- src/test/ui/borrowck/move-in-pattern.stderr | 4 +- .../ui/borrowck/mut-borrow-in-loop-2.stderr | 8 + src/test/ui/borrowck/or-patterns.stderr | 16 ++ .../ui/closure_context/issue-42065.stderr | 4 + src/test/ui/codemap_tests/tab_3.stderr | 4 + src/test/ui/drop/repeat-drop-2.stderr | 5 + src/test/ui/issues/issue-29723.stderr | 5 + src/test/ui/issues/issue-42796.stderr | 4 + src/test/ui/issues/issue-61108.stderr | 4 + src/test/ui/issues/issue-64559.stderr | 4 + .../ui/liveness/liveness-move-call-arg.stderr | 16 +- .../ui/liveness/liveness-move-in-loop.stderr | 14 ++ .../ui/liveness/liveness-move-in-while.stderr | 12 +- .../liveness/liveness-use-after-move.stderr | 4 + .../liveness/liveness-use-after-send.stderr | 9 + .../borrow-closures-instead-of-move.stderr | 22 ++ .../ui/moves/issue-46099-move-in-macro.stderr | 5 + .../ui/moves/issue-72649-uninit-in-loop.rs | 6 +- .../moves/issue-72649-uninit-in-loop.stderr | 10 +- .../ui/moves/move-fn-self-receiver.stderr | 14 ++ .../ui/moves/move-guard-same-consts.stderr | 12 ++ src/test/ui/moves/move-in-guard-1.stderr | 12 ++ src/test/ui/moves/move-in-guard-2.stderr | 12 ++ ...moves-based-on-type-access-to-field.stderr | 4 + ...sed-on-type-cyclic-types-issue-4821.stderr | 2 +- ...-on-type-distribute-copy-over-paren.stderr | 10 + .../ui/moves/moves-based-on-type-exprs.stderr | 60 ++++++ .../moves-based-on-type-match-bindings.stderr | 4 + .../ui/moves/moves-based-on-type-tuple.stderr | 5 + ...se_of_moved_value_clone_suggestions.stderr | 5 + src/test/ui/nll/closure-access-spans.stderr | 10 + .../issue-21232-partial-init-and-use.stderr | 24 +++ src/test/ui/nll/issue-51512.stderr | 5 + src/test/ui/nll/issue-53807.stderr | 2 +- src/test/ui/nll/match-cfg-fake-edges.stderr | 5 + src/test/ui/nll/ref-suggestion.stderr | 12 +- ...can-live-while-the-other-survives-1.stderr | 4 +- .../borrowck-move-and-move.stderr | 31 +++ .../borrowck-pat-at-and-box.stderr | 4 + ...orrowck-pat-by-move-and-ref-inverse.stderr | 23 +++ .../borrowck-pat-by-move-and-ref.stderr | 25 ++- .../copy-and-move-mixed.stderr | 4 + ...inding-modes-both-sides-independent.stderr | 5 + .../borrowck-move-ref-pattern.stderr | 4 + .../dbg-macro-move-semantics.stderr | 6 + .../suggestions/borrow-for-loop-head.stderr | 5 + .../try-block-maybe-bad-lifetime.stderr | 4 + ...ed-closures-infer-fnonce-call-twice.stderr | 4 + ...osures-infer-fnonce-move-call-twice.stderr | 4 + .../ui/union/union-move.mirunsafeck.stderr | 16 ++ .../ui/union/union-move.thirunsafeck.stderr | 16 ++ src/test/ui/unop-move-semantics.stderr | 4 + .../unsized-locals/borrow-after-move.stderr | 13 ++ src/test/ui/unsized-locals/double-move.stderr | 8 + .../use/use-after-move-based-on-type.stderr | 4 + ...after-move-implicity-coerced-object.stderr | 8 + 86 files changed, 1092 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4ad9981991d30..91c46f3d0b5cd 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1376,7 +1376,7 @@ pub enum ExprKind { /// Conditionless loop (can be exited with `break`, `continue`, or `return`). /// /// `'label: loop { block }` - Loop(P<Block>, Option<Label>), + Loop(P<Block>, Option<Label>, Span), /// A `match` block. Match(P<Expr>, Vec<Arm>), /// A closure (e.g., `move |a, b, c| a + b + c`). diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f9ab5a1757085..38196999ae27d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1351,9 +1351,10 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_block(body); visit_opt(label, |label| vis.visit_label(label)); } - ExprKind::Loop(body, label) => { + ExprKind::Loop(body, label, span) => { vis.visit_block(body); visit_opt(label, |label| vis.visit_label(label)); + vis.visit_span(span); } ExprKind::Match(expr, arms) => { vis.visit_expr(expr); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 0978fc94d698d..d9683eb6e57f1 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -824,7 +824,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_block(block); } - ExprKind::Loop(block, opt_label) => { + ExprKind::Loop(block, opt_label, _) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index eaa5a38388afc..9f1f55a55e6ba 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -134,12 +134,12 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) }) } - ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { + ExprKind::Loop(ref body, opt_label, span) => self.with_loop_scope(e.id, |this| { hir::ExprKind::Loop( this.lower_block(body, false), this.lower_label(opt_label), hir::LoopSource::Loop, - DUMMY_SP, + this.lower_span(span), ) }), ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body), diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 1da40d2302e12..4b37fa027f53b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -377,7 +377,7 @@ impl<'a> State<'a> { self.space(); self.print_block_with_attrs(blk, attrs); } - ast::ExprKind::Loop(ref blk, opt_label) => { + ast::ExprKind::Loop(ref blk, opt_label, _) => { if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 9e0aa57b2553f..b5dbf4dac4f24 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -191,6 +191,146 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_loop_move = true; } + struct ExpressionFinder<'hir> { + expr_span: Span, + expr: Option<&'hir hir::Expr<'hir>>, + pat: Option<&'hir hir::Pat<'hir>>, + } + impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { + if e.span == self.expr_span { + self.expr = Some(e); + } + hir::intravisit::walk_expr(self, e); + } + fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) { + if p.span == self.expr_span { + self.pat = Some(p); + } + if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, _) = p.kind + && i.span == self.expr_span + { + self.pat = Some(p); + } + hir::intravisit::walk_pat(self, p); + } + } + + let hir = self.infcx.tcx.hir(); + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, _, body_id), + .. + })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id())) + && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) + { + let place = &self.move_data.move_paths[mpi].place; + let span = place.as_local() + .map(|local| self.body.local_decls[local].source_info.span); + let mut finder = ExpressionFinder { + expr_span: move_span, + expr: None, + pat: None, + }; + finder.visit_expr(expr); + if let Some(span) = span && let Some(expr) = finder.expr { + for (_, expr) in hir.parent_iter(expr.hir_id) { + if let hir::Node::Expr(expr) = expr { + if expr.span.contains(span) { + // If the let binding occurs within the same loop, then that + // loop isn't relevant, like in the following, the outermost `loop` + // doesn't play into `x` being moved. + // ``` + // loop { + // let x = String::new(); + // loop { + // foo(x); + // } + // } + // ``` + break; + } + if let hir::ExprKind::Loop(.., loop_span) = expr.kind { + err.span_label(loop_span, "inside of this loop"); + } + } + } + let typeck = self.infcx.tcx.typeck(self.mir_def_id()); + let hir_id = hir.get_parent_node(expr.hir_id); + if let Some(parent) = hir.find(hir_id) { + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind + && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) + && let Some(def_id) = def_id.as_local() + && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) + && let Some(fn_sig) = node.fn_sig() + && let Some(ident) = node.ident() + && let Some(pos) = args.iter() + .position(|arg| arg.hir_id == expr.hir_id) + && let Some(arg) = fn_sig.decl.inputs.get(pos + 1) + { + let mut span: MultiSpan = arg.span.into(); + span.push_span_label( + arg.span, + "this type parameter takes ownership of the value".to_string(), + ); + span.push_span_label( + ident.span, + "in this method".to_string(), + ); + err.span_note( + span, + format!( + "consider changing this parameter type in `{}` to borrow \ + instead if ownering the value isn't necessary", + ident, + ), + ); + } + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::Call(call, args) = parent_expr.kind + && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() + && let Some(def_id) = def_id.as_local() + && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) + && let Some(fn_sig) = node.fn_sig() + && let Some(ident) = node.ident() + && let Some(pos) = args.iter() + .position(|arg| arg.hir_id == expr.hir_id) + && let Some(arg) = fn_sig.decl.inputs.get(pos) + { + let mut span: MultiSpan = arg.span.into(); + span.push_span_label( + arg.span, + "this type parameter takes ownership of the value".to_string(), + ); + span.push_span_label( + ident.span, + "in this function".to_string(), + ); + err.span_note( + span, + format!( + "consider changing this parameter type in `{}` to borrow \ + instead if ownering the value isn't necessary", + ident, + ), + ); + } + let place = &self.move_data.move_paths[mpi].place; + let ty = place.ty(self.body, self.infcx.tcx).ty; + self.suggest_cloning(&mut err, ty, move_span); + } + } + if let Some(pat) = finder.pat { + in_pattern = true; + err.span_suggestion_verbose( + pat.span.shrink_to_lo(), + "borrow this binding in the pattern to avoid moving the value", + "ref ".to_string(), + Applicability::MachineApplicable, + ); + } + } + self.explain_captures( &mut err, span, @@ -203,25 +343,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_loop_move, maybe_reinitialized_locations.is_empty(), ); - - if let (UseSpans::PatUse(span), []) = - (move_spans, &maybe_reinitialized_locations[..]) - { - if maybe_reinitialized_locations.is_empty() { - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "borrow this field in the pattern to avoid moving {}", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) - .unwrap_or_else(|| "the value".to_string()) - ), - "ref ", - Applicability::MachineApplicable, - ); - in_pattern = true; - } - } } use_spans.var_path_only_subdiag(&mut err, desired_action); @@ -595,6 +716,39 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { true } + fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) { + let tcx = self.infcx.tcx; + + // Try to find predicates on *generic params* that would allow copying `ty` + let infcx = tcx.infer_ctxt().build(); + let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx); + + let clone_did = infcx.tcx.lang_items().clone_trait().unwrap(); + let cause = ObligationCause::new( + span, + self.mir_hir_id(), + rustc_infer::traits::ObligationCauseCode::MiscObligation, + ); + fulfill_cx.register_bound( + &infcx, + self.param_env, + // Erase any region vids from the type, which may not be resolved + infcx.tcx.erase_regions(ty), + clone_did, + cause, + ); + // Select all, including ambiguous predicates + let errors = fulfill_cx.select_all_or_error(&infcx); + if errors.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_hi(), + "consider cloning the value if the performance cost is acceptable", + ".clone()".to_string(), + Applicability::MachineApplicable, + ); + } + } + fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) { let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id()); diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 4b57bdfbc8fb1..de6bac08fdb8c 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -307,7 +307,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::InlineAsm(_) | ExprKind::Let(_, _, _) | ExprKind::Lit(_) - | ExprKind::Loop(_, _) + | ExprKind::Loop(_, _, _) | ExprKind::MacCall(_) | ExprKind::Match(_, _) | ExprKind::Path(_, _) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fe7401786a029..d43509303b8a9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1734,7 +1734,7 @@ impl<'a> Parser<'a> { expr.kind, ExprKind::While(_, _, None) | ExprKind::ForLoop(_, _, _, None) - | ExprKind::Loop(_, None) + | ExprKind::Loop(_, None, _) | ExprKind::Block(_, None) ) { @@ -2444,10 +2444,11 @@ impl<'a> Parser<'a> { /// Parses `loop { ... }` (`loop` token already eaten). fn parse_loop_expr(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { + let loop_span = self.prev_token.span; let (attrs, body) = self.parse_inner_attrs_and_block()?; Ok(self.mk_expr_with_attrs( lo.to(self.prev_token.span), - ExprKind::Loop(body, opt_label), + ExprKind::Loop(body, opt_label, loop_span), attrs, )) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5072d2aad1669..93b0f5814dedf 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3841,7 +3841,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block), + ExprKind::Loop(ref block, label, _) => { + self.resolve_labeled_block(label, expr.id, &block) + } ExprKind::While(ref cond, ref block, label) => { self.with_resolved_label(label, expr.id, |this| { diff --git a/src/test/ui/binding/issue-53114-borrow-checks.stderr b/src/test/ui/binding/issue-53114-borrow-checks.stderr index 489bf70d920a3..0ec2ae8839e79 100644 --- a/src/test/ui/binding/issue-53114-borrow-checks.stderr +++ b/src/test/ui/binding/issue-53114-borrow-checks.stderr @@ -17,6 +17,10 @@ LL | match mm { (_, _y) => { } } | ^^ value used here after partial move | = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | match mm { (ref _x, _) => { } } + | +++ error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:29:11 @@ -28,6 +32,10 @@ LL | match mm { (_, _) => { } } | ^^ value used here after partial move | = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | match mm { (_, ref _y) => { } } + | +++ error[E0382]: use of moved value: `m` --> $DIR/issue-53114-borrow-checks.rs:36:16 @@ -48,6 +56,10 @@ LL | if let (_, _y) = mm { } | ^^ value used here after partial move | = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | if let (ref _x, _) = mm { } + | +++ error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:43:21 @@ -59,6 +71,10 @@ LL | if let (_, _) = mm { } | ^^ value used here after partial move | = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | if let (_, ref _y) = mm { } + | +++ error: aborting due to 6 previous errors diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr index 695b01d5ee3ad..994eaf9d8c778 100644 --- a/src/test/ui/binop/binop-move-semantics.stderr +++ b/src/test/ui/binop/binop-move-semantics.stderr @@ -32,6 +32,10 @@ LL | + LL | x.clone(); | ^^^^^^^^^ value borrowed here after move | +help: consider cloning the value if the performance cost is acceptable + | +LL | x.clone() + | ++++++++ help: consider further restricting this bound | LL | fn move_then_borrow<T: Add<Output=()> + Clone + Copy>(x: T) { diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 1fd1eb128511b..f58672f0666be 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -27,6 +27,11 @@ LL | a @ [.., _] => (), ... LL | &x; | ^^ value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ [.., _] => (), + | +++ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5 @@ -78,6 +83,15 @@ LL | foo @ Some(Test::Foo | Test::Bar) => (), ... LL | &x; | ^^ value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref foo @ Some(Test::Foo | Test::Bar) => (), + | +++ +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref foo @ Some(Test::Foo | Test::Bar) => (), + | +++ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5 @@ -129,6 +143,15 @@ LL | a @ [.., Some(Test::Foo | Test::Bar)] => (), ... LL | &x; | ^^ value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ [.., Some(Test::Foo | Test::Bar)] => (), + | +++ +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ [.., Some(Test::Foo | Test::Bar)] => (), + | +++ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5 diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr index 17b9310661583..00bb13caebdb5 100644 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr +++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -7,6 +7,18 @@ LL | consume(b); | - value moved here LL | consume(b); | ^ value used here after move + | +note: consider changing this parameter type in `consume` to borrow instead if ownering the value isn't necessary + --> $DIR/borrowck-consume-unsize-vec.rs:3:15 + | +LL | fn consume(_: Box<[i32]>) { + | ------- ^^^^^^^^^^ this type parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | consume(b.clone()); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr index 4e20bbf175770..103f45155d7ba 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -7,6 +7,14 @@ LL | consume(b); | - value moved here LL | consume(b); | ^ value used here after move + | +note: consider changing this parameter type in `consume` to borrow instead if ownering the value isn't necessary + --> $DIR/borrowck-consume-upcast-box.rs:5:15 + | +LL | fn consume(_: Box<dyn Foo>) { + | ------- ^^^^^^^^^^^^ this type parameter takes ownership of the value + | | + | in this function error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr index cd0d2fee9422f..eaf4bb38bc590 100644 --- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr +++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr @@ -9,6 +9,11 @@ LL | Some(_) if { drop(my_str); false } => {} LL | Some(_) => {} LL | None => { foo(my_str); } | ^^^^^^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Some(_) if { drop(my_str.clone()); false } => {} + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr index 0dd720ff6ce04..e1b9916208805 100644 --- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr +++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr @@ -7,6 +7,11 @@ LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur | - ^^^^^^^^^ value borrowed here after move | | | value moved here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = {x.clone()} + x.clone(); // the `{x}` forces a move to occur + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr index 346b82a266644..67b00c1dd90ce 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr @@ -8,6 +8,10 @@ LL | [.., _y] => {} | ^^ value used here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-match.rs:23:14 @@ -19,6 +23,10 @@ LL | [.., _y] => {} | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:33:15 @@ -30,6 +38,10 @@ LL | [.., (_y, _)] => {} | ^^ value used here after move | = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:44:11 @@ -41,6 +53,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:55:11 @@ -52,6 +68,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:66:11 @@ -63,6 +83,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:77:11 @@ -74,6 +98,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:89:11 @@ -85,6 +113,10 @@ LL | [(_x, _), _, _] => {} | ^^ value used here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _, _] => {} + | +++ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:99:15 @@ -96,6 +128,10 @@ LL | [.., (_x, _)] => {} | ^^ value used here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _y @ ..] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:110:11 @@ -107,6 +143,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _] => {} + | +++ error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr index 6c6a25c251e70..47429ea3eebae 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr @@ -8,6 +8,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11 @@ -19,6 +23,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11 @@ -30,6 +38,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11 @@ -41,6 +53,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11 @@ -52,6 +68,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11 @@ -63,6 +83,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11 @@ -74,6 +98,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, ref _y @ ..] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11 @@ -85,6 +113,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11 @@ -96,6 +128,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _, _] => {} + | +++ error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr index 77702e145df81..bfab13d42d2a1 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr @@ -8,6 +8,10 @@ LL | [.., ref _y] => {} | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14 @@ -19,6 +23,10 @@ LL | [.., ref _y] => {} | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15 @@ -30,6 +38,10 @@ LL | [.., (ref _y, _)] => {} | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11 @@ -41,6 +53,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11 @@ -52,6 +68,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11 @@ -63,6 +83,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11 @@ -74,6 +98,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11 @@ -85,6 +113,10 @@ LL | [(ref _x, _), _, _] => {} | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _, _] => {} + | +++ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15 @@ -96,6 +128,10 @@ LL | [.., (ref _x, _)] => {} | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _y @ ..] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11 @@ -107,6 +143,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5 @@ -118,6 +158,10 @@ LL | a[2] = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5 @@ -129,6 +173,10 @@ LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5 @@ -140,6 +188,10 @@ LL | a[0] = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x @ ..] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5 @@ -151,6 +203,10 @@ LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x @ ..] => {} + | +++ error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr index 6cc2c2f7a984c..8412c24fe6112 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr @@ -8,6 +8,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11 @@ -19,6 +23,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11 @@ -30,6 +38,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11 @@ -41,6 +53,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11 @@ -52,6 +68,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11 @@ -63,6 +83,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11 @@ -74,6 +98,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, ref _y @ ..] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11 @@ -85,6 +113,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _] => {} + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11 @@ -96,6 +128,10 @@ LL | match a { | ^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _, _] => {} + | +++ error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr index 9add7553afa70..e2aeaafc63c25 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr @@ -7,6 +7,10 @@ LL | let [.., ref _y] = a; | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x] = a; + | +++ error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:16:14 @@ -17,6 +21,10 @@ LL | let [.., ref _y] = a; | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use.rs:22:15 @@ -27,6 +35,10 @@ LL | let [.., (ref _y, _)] = a; | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:30:10 @@ -37,6 +49,10 @@ LL | let [ref _y @ .., _, _] = a; | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _x, _, _] = a; + | +++ error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:36:16 @@ -47,6 +63,10 @@ LL | let [_, _, ref _y @ ..] = a; | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., ref _x] = a; + | +++ error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:42:10 @@ -57,6 +77,10 @@ LL | let [ref _y @ .., _, _] = a; | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [(ref _x, _), _, _] = a; + | +++ error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:48:16 @@ -67,6 +91,10 @@ LL | let [_, _, ref _y @ ..] = a; | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., (ref _x, _)] = a; + | +++ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:54:11 @@ -77,6 +105,10 @@ LL | let [(ref _x, _), _, _] = a; | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _y @ .., _, _] = a; + | +++ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:60:15 @@ -87,6 +119,10 @@ LL | let [.., (ref _x, _)] = a; | ^^^^^^ value borrowed here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _y @ ..] = a; + | +++ error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:68:13 @@ -97,6 +133,10 @@ LL | let [_, ref _y @ ..] = a; | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref x @ .., _] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:76:5 @@ -107,6 +147,10 @@ LL | a[2] = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:82:5 @@ -117,6 +161,10 @@ LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:88:5 @@ -127,6 +175,10 @@ LL | a[0] = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x @ ..] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:94:5 @@ -137,6 +189,10 @@ LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x @ ..] = a; + | +++ error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr index 363effcfe5322..dd456681f57bc 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -7,6 +7,10 @@ LL | let [.., _y] = a; | ^^ value used here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x] = a; + | +++ error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array.rs:16:14 @@ -17,6 +21,10 @@ LL | let [.., _y] = a; | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:22:15 @@ -27,6 +35,10 @@ LL | let [.., (_y, _)] = a; | ^^ value used here after move | = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:30:10 @@ -37,6 +49,10 @@ LL | let [_y @ .., _, _] = a; | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _x, _, _] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:36:16 @@ -47,6 +63,10 @@ LL | let [_, _, _y @ ..] = a; | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., ref _x] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:42:10 @@ -57,6 +77,10 @@ LL | let [_y @ .., _, _] = a; | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [(ref _x, _), _, _] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:48:16 @@ -67,6 +91,10 @@ LL | let [_, _, _y @ ..] = a; | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., (ref _x, _)] = a; + | +++ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:54:11 @@ -77,6 +105,10 @@ LL | let [(_x, _), _, _] = a; | ^^ value used here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _y @ .., _, _] = a; + | +++ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:60:15 @@ -87,6 +119,10 @@ LL | let [.., (_x, _)] = a; | ^^ value used here after move | = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _y @ ..] = a; + | +++ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:68:13 @@ -97,6 +133,10 @@ LL | let [_, _y @ ..] = a; | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref x @ .., _] = a; + | +++ error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.stderr index 86d2955e2364f..f94cbc30db421 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.stderr @@ -40,6 +40,11 @@ LL | thread::spawn(move|| { ... LL | drop(x1); | -- use occurs due to use in closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x1.clone()); + | ++++++++ error[E0382]: use of moved value: `x2` --> $DIR/borrowck-multiple-captures.rs:27:19 @@ -53,6 +58,11 @@ LL | thread::spawn(move|| { ... LL | drop(x2); | -- use occurs due to use in closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x2.clone()); + | ++++++++ error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:41:14 @@ -100,6 +110,11 @@ LL | thread::spawn(move|| { LL | LL | drop(x); | - use occurs due to use in closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x.clone()); + | ++++++++ error: aborting due to 8 previous errors diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr index e01c26adcfc2d..fb0e274c2919a 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr @@ -33,6 +33,11 @@ LL | println!("{}", f[s]); ... LL | f[s] = 10; | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | println!("{}", f[s.clone()]); + | ++++++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr index 22253cd96f1a6..f785900d53fc0 100644 --- a/src/test/ui/borrowck/borrowck-reinit.stderr +++ b/src/test/ui/borrowck/borrowck-reinit.stderr @@ -8,6 +8,11 @@ LL | drop(x); | - value moved here LL | let _ = (1,x); | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x.clone()); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr index d33115988a9a8..ad898fcabd9db 100644 --- a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr +++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr @@ -8,6 +8,11 @@ LL | Some(_) if { drop(a); false } => None, | - value moved here LL | x => x, | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Some(_) if { drop(a.clone()); false } => None, + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr index b20cc6d8cf59f..716cc9d0c8ba2 100644 --- a/src/test/ui/borrowck/issue-41962.stderr +++ b/src/test/ui/borrowck/issue-41962.stderr @@ -5,7 +5,7 @@ LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `maybe.0` +help: borrow this binding in the pattern to avoid moving the value | LL | if let Some(ref thing) = maybe { | +++ diff --git a/src/test/ui/borrowck/issue-83760.stderr b/src/test/ui/borrowck/issue-83760.stderr index beeda5685dc09..2552fff860cd3 100644 --- a/src/test/ui/borrowck/issue-83760.stderr +++ b/src/test/ui/borrowck/issue-83760.stderr @@ -8,6 +8,10 @@ LL | val = None; | ---------- this reinitialization might get skipped | = note: move occurs because value has type `Struct`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | while let Some(ref foo) = val { + | +++ error[E0382]: use of moved value: `foo` --> $DIR/issue-83760.rs:21:14 diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr index c6931ba72579b..55948afca733b 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr +++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr @@ -5,7 +5,7 @@ LL | if let Some(mut _x) = opt {} | ^^^^^^ value moved here, in previous iteration of loop | = note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `opt.0` +help: borrow this binding in the pattern to avoid moving the value | LL | if let Some(ref mut _x) = opt {} | +++ diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr index 2bf34b32176c0..dd3471e2c8be5 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut.stderr +++ b/src/test/ui/borrowck/move-in-pattern-mut.stderr @@ -8,7 +8,7 @@ LL | foo(s); | ^ value used here after partial move | = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `s.0` +help: borrow this binding in the pattern to avoid moving the value | LL | if let Some(ref mut x) = s { | +++ @@ -23,7 +23,7 @@ LL | bar(e); | ^ value used here after partial move | = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `e.s` +help: borrow this binding in the pattern to avoid moving the value | LL | let E::V { s: ref mut x } = e; | +++ diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr index 6b84c0032cdde..250acbe5928a0 100644 --- a/src/test/ui/borrowck/move-in-pattern.stderr +++ b/src/test/ui/borrowck/move-in-pattern.stderr @@ -8,7 +8,7 @@ LL | foo(s); | ^ value used here after partial move | = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `s.0` +help: borrow this binding in the pattern to avoid moving the value | LL | if let Some(ref x) = s { | +++ @@ -23,7 +23,7 @@ LL | bar(e); | ^ value used here after partial move | = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `e.s` +help: borrow this binding in the pattern to avoid moving the value | LL | let E::V { s: ref x } = e; | +++ diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr index 8b05b23882273..eaf53868014fa 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr +++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr @@ -4,9 +4,17 @@ error[E0382]: use of moved value: `value` LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) { | ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait LL | for _ in 0..3 { + | ------------- inside of this loop LL | Other::handle(value); | ^^^^^ value moved here, in previous iteration of loop | +note: consider changing this parameter type in `handle` to borrow instead if ownering the value isn't necessary + --> $DIR/mut-borrow-in-loop-2.rs:9:22 + | +LL | fn handle(value: T) -> Self; + | ------ ^ this type parameter takes ownership of the value + | | + | in this function help: consider creating a fresh reborrow of `value` here | LL | Other::handle(&mut *value); diff --git a/src/test/ui/borrowck/or-patterns.stderr b/src/test/ui/borrowck/or-patterns.stderr index dd5797c3f79cc..9501798bb06d0 100644 --- a/src/test/ui/borrowck/or-patterns.stderr +++ b/src/test/ui/borrowck/or-patterns.stderr @@ -8,6 +8,10 @@ LL | &x.0 .0; | ^^^^^^^ value borrowed here after move | = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ((ref y, _) | (_, y),) => (), + | +++ error[E0382]: borrow of moved value: `x.0.1` --> $DIR/or-patterns.rs:10:5 @@ -19,6 +23,10 @@ LL | &x.0 .1; | ^^^^^^^ value borrowed here after move | = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ((y, _) | (_, ref y),) => (), + | +++ error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable --> $DIR/or-patterns.rs:18:5 @@ -77,6 +85,10 @@ LL | &x.0 .0; | ^^^^^^^ value borrowed here after move | = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ((ref y, _) | (_, y),) = x; + | +++ error[E0382]: borrow of moved value: `x.0.1` --> $DIR/or-patterns.rs:40:5 @@ -88,6 +100,10 @@ LL | &x.0 .1; | ^^^^^^^ value borrowed here after move | = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ((y, _) | (_, ref y),) = x; + | +++ error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable --> $DIR/or-patterns.rs:46:5 diff --git a/src/test/ui/closure_context/issue-42065.stderr b/src/test/ui/closure_context/issue-42065.stderr index 896bb6dc6bee8..4e436ca7c03f5 100644 --- a/src/test/ui/closure_context/issue-42065.stderr +++ b/src/test/ui/closure_context/issue-42065.stderr @@ -16,6 +16,10 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | debug_dump_dict(); | ^^^^^^^^^^^^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | debug_dump_dict.clone()(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr index 9072cc925ffff..080f6c39449f0 100644 --- a/src/test/ui/codemap_tests/tab_3.stderr +++ b/src/test/ui/codemap_tests/tab_3.stderr @@ -15,6 +15,10 @@ note: this function takes ownership of the receiver `self`, which moves `some_ve LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | some_vec.clone().into_iter(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr index 7357551c4a7f6..f030228f71ae4 100644 --- a/src/test/ui/drop/repeat-drop-2.stderr +++ b/src/test/ui/drop/repeat-drop-2.stderr @@ -7,6 +7,11 @@ LL | let _bar = foo; | --- value moved here LL | let _baz = [foo; 0]; | ^^^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _bar = foo.clone(); + | ++++++++ error[E0493]: destructor of `String` cannot be evaluated at compile-time --> $DIR/repeat-drop-2.rs:7:25 diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr index e39ddfc81c968..92ee5cf22b719 100644 --- a/src/test/ui/issues/issue-29723.stderr +++ b/src/test/ui/issues/issue-29723.stderr @@ -9,6 +9,11 @@ LL | 0 if { drop(s); false } => String::from("oops"), ... LL | s | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | 0 if { drop(s.clone()); false } => String::from("oops"), + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42796.stderr b/src/test/ui/issues/issue-42796.stderr index f3e0e7b20a178..f2971df5db275 100644 --- a/src/test/ui/issues/issue-42796.stderr +++ b/src/test/ui/issues/issue-42796.stderr @@ -10,6 +10,10 @@ LL | println!("{}", s); | ^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | let mut s_copy = s.clone(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index e5b671d7b7ab0..0f6f30531b332 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -14,6 +14,10 @@ note: this function takes ownership of the receiver `self`, which moves `bad_let | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | for l in bad_letters.clone() { + | ++++++++ help: consider iterating over a slice of the `Vec<char>`'s content to avoid moving into the `for` loop | LL | for l in &bad_letters { diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index ef178bbd15538..5c04cefa5304b 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -15,6 +15,10 @@ note: this function takes ownership of the receiver `self`, which moves `orig` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | for _val in orig.clone() {} + | ++++++++ help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop | LL | for _val in &orig {} diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index 7c0e916eddcaa..bd45aa5345885 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -3,9 +3,23 @@ error[E0382]: use of moved value: `x` | LL | let x: Box<isize> = Box::new(25); | - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait -... +LL | +LL | loop { + | ---- inside of this loop LL | take(x); | ^ value moved here, in previous iteration of loop + | +note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary + --> $DIR/liveness-move-call-arg.rs:1:13 + | +LL | fn take(_x: Box<isize>) {} + | ---- ^^^^^^^^^^ this type parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | take(x.clone()); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/liveness/liveness-move-in-loop.stderr b/src/test/ui/liveness/liveness-move-in-loop.stderr index 832d4f8fa030f..a060914f17859 100644 --- a/src/test/ui/liveness/liveness-move-in-loop.stderr +++ b/src/test/ui/liveness/liveness-move-in-loop.stderr @@ -4,8 +4,22 @@ error[E0382]: use of moved value: `y` LL | let y: Box<isize> = 42.into(); | - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait ... +LL | loop { + | ---- inside of this loop +LL | println!("{}", y); +LL | loop { + | ---- inside of this loop +LL | loop { + | ---- inside of this loop +LL | loop { + | ---- inside of this loop LL | x = y; | ^ value moved here, in previous iteration of loop + | +help: consider cloning the value if the performance cost is acceptable + | +LL | x = y.clone(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr index b04a05fe40906..4dff7447dd766 100644 --- a/src/test/ui/liveness/liveness-move-in-while.stderr +++ b/src/test/ui/liveness/liveness-move-in-while.stderr @@ -24,12 +24,22 @@ error[E0382]: borrow of moved value: `y` LL | let y: Box<isize> = 42.into(); | - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait ... +LL | loop { + | ---- inside of this loop LL | println!("{}", y); | ^ value borrowed here after move LL | while true { while true { while true { x = y; x.clone(); } } } - | - value moved here, in previous iteration of loop + | ---------- ---------- ---------- - value moved here, in previous iteration of loop + | | | | + | | | inside of this loop + | | inside of this loop + | inside of this loop | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | while true { while true { while true { x = y.clone(); x.clone(); } } } + | ++++++++ error: aborting due to previous error; 3 warnings emitted diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr index 218b93c8e4f45..3accba197a13d 100644 --- a/src/test/ui/liveness/liveness-use-after-move.stderr +++ b/src/test/ui/liveness/liveness-use-after-move.stderr @@ -10,6 +10,10 @@ LL | println!("{}", *x); | ^^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | let y = x.clone(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr index 8edc0463fe571..c407827d32050 100644 --- a/src/test/ui/liveness/liveness-use-after-send.stderr +++ b/src/test/ui/liveness/liveness-use-after-send.stderr @@ -8,7 +8,16 @@ LL | send(ch, message); LL | println!("{}", message); | ^^^^^^^ value borrowed here after move | +note: consider changing this parameter type in `send` to borrow instead if ownering the value isn't necessary + --> $DIR/liveness-use-after-send.rs:3:54 + | +LL | fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) { + | ---- in this function ^ this type parameter takes ownership of the value = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | send(ch, message.clone()); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr index 3146b6959001e..11fcb1cc26381 100644 --- a/src/test/ui/moves/borrow-closures-instead-of-move.stderr +++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr @@ -4,9 +4,17 @@ error[E0382]: use of moved value: `f` LL | fn takes_fn(f: impl Fn()) { | - move occurs because `f` has type `impl Fn()`, which does not implement the `Copy` trait LL | loop { + | ---- inside of this loop LL | takes_fnonce(f); | ^ value moved here, in previous iteration of loop | +note: consider changing this parameter type in `takes_fnonce` to borrow instead if ownering the value isn't necessary + --> $DIR/borrow-closures-instead-of-move.rs:34:20 + | +LL | fn takes_fnonce(_: impl FnOnce()) {} + | ------------ ^^^^^^^^^^^^^ this type parameter takes ownership of the value + | | + | in this function help: consider borrowing `f` | LL | takes_fnonce(&f); @@ -24,6 +32,13 @@ LL | takes_fnonce(m); LL | takes_fnonce(m); | ^ value used here after move | +note: consider changing this parameter type in `takes_fnonce` to borrow instead if ownering the value isn't necessary + --> $DIR/borrow-closures-instead-of-move.rs:34:20 + | +LL | fn takes_fnonce(_: impl FnOnce()) {} + | ------------ ^^^^^^^^^^^^^ this type parameter takes ownership of the value + | | + | in this function help: consider mutably borrowing `m` | LL | takes_fnonce(&mut m); @@ -43,6 +58,13 @@ note: closure cannot be moved more than once as it is not `Copy` due to moving t | LL | x += 1; | ^ +note: consider changing this parameter type in `takes_fnonce` to borrow instead if ownering the value isn't necessary + --> $DIR/borrow-closures-instead-of-move.rs:34:20 + | +LL | fn takes_fnonce(_: impl FnOnce()) {} + | ------------ ^^^^^^^^^^^^^ this type parameter takes ownership of the value + | | + | in this function help: consider mutably borrowing `closure` | LL | takes_fnonce(&mut closure); diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr index baa87e3e9fdb2..94bc9e6f45465 100644 --- a/src/test/ui/moves/issue-46099-move-in-macro.stderr +++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr @@ -5,6 +5,11 @@ LL | let b = Box::new(true); | - move occurs because `b` has type `Box<bool>`, which does not implement the `Copy` trait LL | test!({b}); | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | test!({b.clone()}); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.rs b/src/test/ui/moves/issue-72649-uninit-in-loop.rs index d76b69ecdc8bb..56c225bab8cbc 100644 --- a/src/test/ui/moves/issue-72649-uninit-in-loop.rs +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.rs @@ -25,7 +25,7 @@ fn moved_here_1() { fn moved_here_2() { let value = NonCopy{}; //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait - loop { + loop { //~ NOTE inside of this loop let _used = value; //~^ NOTE value moved here loop { @@ -38,7 +38,7 @@ fn moved_here_2() { fn moved_loop_1() { let value = NonCopy{}; //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait - loop { + loop { //~ NOTE inside of this loop let _used = value; //~ ERROR use of moved value: `value` //~^ NOTE value moved here, in previous iteration of loop } @@ -49,7 +49,7 @@ fn moved_loop_2() { //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait let _used = value; value = NonCopy{}; - loop { + loop { //~ NOTE inside of this loop let _used2 = value; //~ ERROR use of moved value: `value` //~^ NOTE value moved here, in previous iteration of loop } diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr index 974994223a3fd..7e119fe8cda64 100644 --- a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr @@ -15,7 +15,9 @@ error[E0382]: use of moved value: `value` | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait -... +LL | +LL | loop { + | ---- inside of this loop LL | let _used = value; | ----- value moved here ... @@ -27,7 +29,9 @@ error[E0382]: use of moved value: `value` | LL | let value = NonCopy{}; | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait -... +LL | +LL | loop { + | ---- inside of this loop LL | let _used = value; | ^^^^^ value moved here, in previous iteration of loop @@ -37,6 +41,8 @@ error[E0382]: use of moved value: `value` LL | let mut value = NonCopy{}; | --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait ... +LL | loop { + | ---- inside of this loop LL | let _used2 = value; | ^^^^^ value moved here, in previous iteration of loop diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr index 3a686121a9283..b331b10a3b79e 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -96,6 +96,10 @@ note: this function takes ownership of the receiver `self`, which moves `rc_foo` | LL | fn use_rc_self(self: Rc<Self>) {} | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | rc_foo.clone().use_rc_self(); + | ++++++++ error[E0382]: use of moved value: `foo_add` --> $DIR/move-fn-self-receiver.rs:59:5 @@ -123,6 +127,10 @@ LL | for _val in implicit_into_iter {} LL | implicit_into_iter; | ^^^^^^^^^^^^^^^^^^ value used here after move | +help: consider cloning the value if the performance cost is acceptable + | +LL | for _val in implicit_into_iter.clone() {} + | ++++++++ help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop | LL | for _val in &implicit_into_iter {} @@ -137,6 +145,11 @@ LL | for _val in explicit_into_iter.into_iter() {} | ----------- `explicit_into_iter` moved due to this method call LL | explicit_into_iter; | ^^^^^^^^^^^^^^^^^^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | for _val in explicit_into_iter.clone().into_iter() {} + | ++++++++ error[E0382]: use of moved value: `container` --> $DIR/move-fn-self-receiver.rs:71:5 @@ -160,6 +173,7 @@ error[E0382]: use of moved value: `foo2` LL | let foo2 = Foo; | ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait LL | loop { + | ---- inside of this loop LL | foo2.use_self(); | ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 2048fefefa31b..04a41b9ce2623 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -8,6 +8,18 @@ LL | (1, 2) if take(x) => (), | - value moved here LL | (1, 2) if take(x) => (), | ^ value used here after move + | +note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary + --> $DIR/move-guard-same-consts.rs:25:15 + | +LL | fn take<T>(_: T) -> bool { false } + | ---- ^ this type parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | (1, 2) if take(x.clone()) => (), + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index 5e9aa66b90dae..d435426f2ec97 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -8,6 +8,18 @@ LL | (1, _) if take(x) => (), | - value moved here LL | (_, 2) if take(x) => (), | ^ value used here after move + | +note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary + --> $DIR/move-in-guard-1.rs:15:15 + | +LL | fn take<T>(_: T) -> bool { false } + | ---- ^ this type parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | (1, _) if take(x.clone()) => (), + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index 8d636c11b78c7..0f4895c2ac132 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -6,6 +6,18 @@ LL | let x: Box<_> = Box::new(1); ... LL | (_, 2) if take(x) => (), | ^ value used here after move + | +note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary + --> $DIR/move-in-guard-2.rs:13:15 + | +LL | fn take<T>(_: T) -> bool { false } + | ---- ^ this type parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | (_, 2) if take(x.clone()) => (), + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr index 3cc8ca29144ca..a49ee31b46622 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -13,6 +13,10 @@ note: this function takes ownership of the receiver `self`, which moves `x` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | consume(x.clone().into_iter().next().unwrap()); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr index a315bbaab33c0..db4382b58fcb2 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr @@ -8,7 +8,7 @@ LL | consume(node) + r | ^^^^ value used here after partial move | = note: partial move occurs because value has type `Box<List>`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `node.next.0` +help: borrow this binding in the pattern to avoid moving the value | LL | Some(ref right) => consume(right), | +++ diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr index ee7971691a4a1..0930df148059d 100644 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr @@ -9,6 +9,11 @@ LL | let _y = Foo { f:x }; LL | LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = Foo { f:x.clone() }; + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:21:11 @@ -21,6 +26,11 @@ LL | let _y = Foo { f:(((x))) }; LL | LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = Foo { f:(((x))).clone() }; + | ++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 9bcec36740d62..78138d214f9a4 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -7,6 +7,11 @@ LL | let _y = Foo { f:x }; | - value moved here LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = Foo { f:x.clone() }; + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:18:11 @@ -17,6 +22,11 @@ LL | let _y = (x, 3); | - value moved here LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = (x.clone(), 3); + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:35:11 @@ -29,6 +39,11 @@ LL | x ... LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | x.clone() + | ++++++++ error[E0382]: borrow of moved value: `y` --> $DIR/moves-based-on-type-exprs.rs:36:11 @@ -41,6 +56,11 @@ LL | y ... LL | touch(&y); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | y.clone() + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:46:11 @@ -53,6 +73,11 @@ LL | true => x, ... LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | true => x.clone(), + | ++++++++ error[E0382]: borrow of moved value: `y` --> $DIR/moves-based-on-type-exprs.rs:47:11 @@ -65,6 +90,11 @@ LL | false => y ... LL | touch(&y); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | false => y.clone() + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:58:11 @@ -77,6 +107,18 @@ LL | _ if guard(x) => 10, ... LL | touch(&x); | ^^ value borrowed here after move + | +note: consider changing this parameter type in `guard` to borrow instead if ownering the value isn't necessary + --> $DIR/moves-based-on-type-exprs.rs:6:14 + | +LL | fn guard(_s: String) -> bool {panic!()} + | ----- ^^^^^^ this type parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | _ if guard(x.clone()) => 10, + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:65:11 @@ -87,6 +129,11 @@ LL | let _y = [x]; | - value moved here LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = [x.clone()]; + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:71:11 @@ -97,6 +144,11 @@ LL | let _y = vec![x]; | - value moved here LL | touch(&x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = vec![x.clone()]; + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:77:11 @@ -113,6 +165,10 @@ note: this function takes ownership of the receiver `self`, which moves `x` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = x.clone().into_iter().next().unwrap(); + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:83:11 @@ -129,6 +185,10 @@ note: this function takes ownership of the receiver `self`, which moves `x` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = [x.clone().into_iter().next().unwrap(); 1]; + | ++++++++ error: aborting due to 11 previous errors diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr index ad1a2db8b52ba..225935532ead7 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr @@ -8,6 +8,10 @@ LL | touch(&x); | ^^ value borrowed here after partial move | = note: partial move occurs because `x.f` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | Foo {ref f} => {} + | +++ error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr index eef8ce61fa9d8..0bcce30126306 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.stderr +++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr @@ -8,6 +8,11 @@ LL | Box::new((x, x)) | - ^ value used here after move | | | value moved here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Box::new((x.clone(), x)) + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr index c25981e6f8063..22e7951dbe367 100644 --- a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr +++ b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr @@ -7,6 +7,11 @@ LL | (t, t) | - ^ value used here after move | | | value moved here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | (t.clone(), t) + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr index e9d7ca953d65b..0a09353b8ec0a 100644 --- a/src/test/ui/nll/closure-access-spans.stderr +++ b/src/test/ui/nll/closure-access-spans.stderr @@ -67,6 +67,11 @@ LL | || x.len(); | ^^ - borrow occurs due to use in closure | | | value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let r = x.clone(); + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:40:5 @@ -79,6 +84,11 @@ LL | || x = String::new(); | ^^ - borrow occurs due to use in closure | | | value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let r = x.clone(); + | ++++++++ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:45:5 diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr index 947c9e29b4508..97ed414b1eceb 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr @@ -37,6 +37,11 @@ LL | let mut t: T = (0, Box::new(0)); drop(t); | move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait LL | t.0 = 10; t.1 = Box::new(20); | ^^^^^^^^ value partially assigned here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let mut t: T = (0, Box::new(0)); drop(t.clone()); + | ++++++++ error[E0381]: partially assigned binding `s` isn't fully initialized --> $DIR/issue-21232-partial-init-and-use.rs:123:5 @@ -77,6 +82,11 @@ LL | let mut t: T = (0, Box::new(0)); drop(t); | move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait LL | t.0 = 10; | ^^^^^^^^ value partially assigned here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let mut t: T = (0, Box::new(0)); drop(t.clone()); + | ++++++++ error[E0381]: partially assigned binding `s` isn't fully initialized --> $DIR/issue-21232-partial-init-and-use.rs:149:5 @@ -208,6 +218,11 @@ LL | c2 => { | -- value moved here LL | c.0 = 2; | ^^^^^^^ value partially assigned here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref c2 => { + | +++ error[E0382]: assign to part of moved value: `c` --> $DIR/issue-21232-partial-init-and-use.rs:255:13 @@ -219,6 +234,11 @@ LL | c2 => { | -- value moved here LL | (c.1).0 = 2; | ^^^^^^^^^^^ value partially assigned here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref c2 => { + | +++ error[E0382]: assign to part of moved value: `c.1` --> $DIR/issue-21232-partial-init-and-use.rs:263:13 @@ -229,6 +249,10 @@ LL | ((c.1).1).0 = 3; | ^^^^^^^^^^^^^^^ value partially assigned here after move | = note: move occurs because `c.1` has type `(i32, (i32, String))`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref c2 => { + | +++ error: aborting due to 23 previous errors diff --git a/src/test/ui/nll/issue-51512.stderr b/src/test/ui/nll/issue-51512.stderr index e591ca08290eb..072e96788b17e 100644 --- a/src/test/ui/nll/issue-51512.stderr +++ b/src/test/ui/nll/issue-51512.stderr @@ -7,6 +7,11 @@ LL | let r = range; | ----- value moved here LL | let x = range.start; | ^^^^^^^^^^^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let r = range.clone(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr index 574a114340f03..d8f58b591311d 100644 --- a/src/test/ui/nll/issue-53807.stderr +++ b/src/test/ui/nll/issue-53807.stderr @@ -5,7 +5,7 @@ LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `maybe.0` +help: borrow this binding in the pattern to avoid moving the value | LL | if let Some(ref thing) = maybe { | +++ diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr index 2d48a914218fd..f72ed3af71823 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.stderr +++ b/src/test/ui/nll/match-cfg-fake-edges.stderr @@ -26,6 +26,11 @@ LL | false if { drop(x); true } => 1, LL | true => { LL | x; | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | false if { drop(x.clone()); true } => 1, + | ++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ref-suggestion.stderr b/src/test/ui/nll/ref-suggestion.stderr index a973c583a9d66..b1f5117cb0243 100644 --- a/src/test/ui/nll/ref-suggestion.stderr +++ b/src/test/ui/nll/ref-suggestion.stderr @@ -7,6 +7,11 @@ LL | let y = x; | - value moved here LL | x; | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let y = x.clone(); + | ++++++++ error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:8:5 @@ -17,6 +22,11 @@ LL | let mut y = x; | - value moved here LL | x; | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let mut y = x.clone(); + | ++++++++ error[E0382]: use of partially moved value: `x` --> $DIR/ref-suggestion.rs:16:5 @@ -28,7 +38,7 @@ LL | x; | ^ value used here after partial move | = note: partial move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `x.0.0` +help: borrow this binding in the pattern to avoid moving the value | LL | (Some(ref y), ()) => {}, | +++ diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index fad84dda0e192..e79e4e7dfa336 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -45,7 +45,7 @@ LL | Some(ref _y @ _z) => {} | value borrowed here after move | = note: move occurs because value has type `X`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `x.0` +help: borrow this binding in the pattern to avoid moving the value | LL | Some(ref _y @ ref _z) => {} | +++ @@ -59,7 +59,7 @@ LL | Some(ref mut _y @ _z) => {} | value borrowed here after move | = note: move occurs because value has type `X`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving `x.0` +help: borrow this binding in the pattern to avoid moving the value | LL | Some(ref mut _y @ ref _z) => {} | +++ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index a227cc583d68d..077583dd2527c 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -6,6 +6,11 @@ LL | let a @ b = U; | | | | | value moved here | value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ ref b = U; + | +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:13:9 @@ -16,6 +21,10 @@ LL | let a @ (b, c) = (U, U); | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (b, ref c) = (U, U); + | +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:15:9 @@ -26,6 +35,10 @@ LL | let a @ (b, c) = (u(), u()); | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (b, ref c) = (u(), u()); + | +++ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:18:16 @@ -36,6 +49,11 @@ LL | a @ Ok(b) | a @ Err(b) => {} | - ^ value used here after move | | | value moved here + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Ok(b) | a @ Err(b) => {} + | +++ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:18:29 @@ -46,6 +64,11 @@ LL | a @ Ok(b) | a @ Err(b) => {} | - ^ value used here after move | | | value moved here + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | a @ Ok(b) | ref a @ Err(b) => {} + | +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:25:9 @@ -56,6 +79,10 @@ LL | xs @ [a, .., b] => {} | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | xs @ [a, .., ref b] => {} + | +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:29:9 @@ -66,6 +93,10 @@ LL | xs @ [_, ys @ .., _] => {} | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | xs @ [_, ref ys @ .., _] => {} + | +++ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:22:12 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 002c7609f6109..f27df32ccfa5c 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -79,6 +79,10 @@ LL | let ref a @ box b = Box::new(NC); | value borrowed here after move | = note: move occurs because value has type `NC`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ box ref b = Box::new(NC); + | +++ error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:38:9 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index a9e66de084242..a41ebf1931f94 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -267,6 +267,10 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (U, U); + | +++ error[E0382]: use of partially moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9 @@ -277,6 +281,10 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u()); + | +++ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38 @@ -285,6 +293,11 @@ LL | match Some((U, U)) { | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | - value moved here ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | +++ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30 @@ -305,6 +318,11 @@ LL | a @ Some(ref b) => {} | - ^^^^^ value borrowed here after move | | | value moved here + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some(ref b) => {} + | +++ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38 @@ -313,6 +331,11 @@ LL | match Some((u(), u())) { | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | - value moved here ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | +++ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index b2f22fe86388e..770bb89530cca 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -242,6 +242,10 @@ LL | let ref mut a @ [b, mut c] = [U, U]; | value borrowed here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref mut a @ [b, ref mut c] = [U, U]; + | +++ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 @@ -251,6 +255,11 @@ LL | let ref a @ b = u(); | | | | | value moved here | value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ ref b = u(); + | +++ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18 @@ -261,6 +270,10 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ (ref b @ ref mut c, ref d @ e) = (u(), u()); + | +++ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33 @@ -271,6 +284,10 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ (ref b @ mut c, ref d @ ref e) = (u(), u()); + | +++ error[E0382]: borrow of partially moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9 @@ -281,6 +298,10 @@ LL | let ref mut a @ [b, mut c] = [u(), u()]; | value borrowed here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref mut a @ [b, ref mut c] = [u(), u()]; + | +++ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 @@ -291,7 +312,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving the value +help: borrow this binding in the pattern to avoid moving the value | LL | ref a @ Some((ref b @ ref mut c, ref d @ e)) => {} | +++ @@ -305,7 +326,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait -help: borrow this field in the pattern to avoid moving the value +help: borrow this binding in the pattern to avoid moving the value | LL | ref a @ Some((ref b @ mut c, ref d @ ref e)) => {} | +++ diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr index cd3234952fa54..4ea3dfefb77a3 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -7,6 +7,10 @@ LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | value used here after partial move | = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ NC(b, ref c @ NC(d, e)) = NC(C, NC(C, C)); + | +++ error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index 840a513d6c67d..43e4b6990d2a2 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -52,6 +52,11 @@ LL | let ref mut a @ b = NotCopy; | | | | | value moved here | value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref mut a @ ref b = NotCopy; + | +++ error: aborting due to 6 previous errors diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index bac2db6ce825c..bb7b818368b78 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -129,6 +129,10 @@ LL | drop(tup.1); | ^^^^^ value used here after move | = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let (ref _x0, ref _x1, ref _x2, ..) = tup; + | +++ error[E0382]: borrow of moved value: `tup.1` --> $DIR/borrowck-move-ref-pattern.rs:29:20 diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index 5611b5f4ece5f..06699b947be40 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -7,6 +7,12 @@ LL | let _ = dbg!(a); | ------- value moved here LL | let _ = dbg!(a); | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + --> $SRC_DIR/std/src/macros.rs:LL:COL + | +LL | ref tmp => { + | +++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr index 1059e3d1525aa..7cd411dde6c21 100644 --- a/src/test/ui/suggestions/borrow-for-loop-head.stderr +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -12,6 +12,7 @@ error[E0382]: use of moved value: `a` LL | let a = vec![1, 2, 3]; | - move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait LL | for i in &a { + | ----------- inside of this loop LL | for j in a { | ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop | @@ -20,6 +21,10 @@ note: this function takes ownership of the receiver `self`, which moves `a` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | for j in a.clone() { + | ++++++++ help: consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop | LL | for j in &a { diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr index c9f2a3ed9f4bf..f738b03eed6b8 100644 --- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr +++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr @@ -23,6 +23,10 @@ LL | println!("{}", x); | ^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | ::std::mem::drop(x.clone()); + | ++++++++ error[E0506]: cannot assign to `i` because it is borrowed --> $DIR/try-block-maybe-bad-lifetime.rs:40:9 diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr index ab6f06518467c..3175d2942d5a7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr @@ -16,6 +16,10 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | tick(); | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | tick.clone()(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr index 8d70a2b17602b..ffeafb10fda2c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr @@ -16,6 +16,10 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | tick(); | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | tick.clone()(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr index 53050cf539eaf..91f2eaad944eb 100644 --- a/src/test/ui/union/union-move.mirunsafeck.stderr +++ b/src/test/ui/union/union-move.mirunsafeck.stderr @@ -8,6 +8,14 @@ LL | move_out(x.f1_nocopy); | ----------- value moved here LL | move_out(x.f2_nocopy); | ^^^^^^^^^^^ value used here after move + | +note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary + --> $DIR/union-move.rs:10:19 + | +LL | fn move_out<T>(x: T) {} + | -------- ^ this type parameter takes ownership of the value + | | + | in this function error[E0382]: use of moved value: `x` --> $DIR/union-move.rs:45:18 @@ -19,6 +27,14 @@ LL | move_out(x.f2_nocopy); | ----------- value moved here LL | move_out(x.f3_copy); | ^^^^^^^^^ value used here after move + | +note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary + --> $DIR/union-move.rs:10:19 + | +LL | fn move_out<T>(x: T) {} + | -------- ^ this type parameter takes ownership of the value + | | + | in this function error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait --> $DIR/union-move.rs:52:18 diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr index 53050cf539eaf..91f2eaad944eb 100644 --- a/src/test/ui/union/union-move.thirunsafeck.stderr +++ b/src/test/ui/union/union-move.thirunsafeck.stderr @@ -8,6 +8,14 @@ LL | move_out(x.f1_nocopy); | ----------- value moved here LL | move_out(x.f2_nocopy); | ^^^^^^^^^^^ value used here after move + | +note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary + --> $DIR/union-move.rs:10:19 + | +LL | fn move_out<T>(x: T) {} + | -------- ^ this type parameter takes ownership of the value + | | + | in this function error[E0382]: use of moved value: `x` --> $DIR/union-move.rs:45:18 @@ -19,6 +27,14 @@ LL | move_out(x.f2_nocopy); | ----------- value moved here LL | move_out(x.f3_copy); | ^^^^^^^^^ value used here after move + | +note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary + --> $DIR/union-move.rs:10:19 + | +LL | fn move_out<T>(x: T) {} + | -------- ^ this type parameter takes ownership of the value + | | + | in this function error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait --> $DIR/union-move.rs:52:18 diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr index 65d866c716e0e..d52a92b8888e8 100644 --- a/src/test/ui/unop-move-semantics.stderr +++ b/src/test/ui/unop-move-semantics.stderr @@ -14,6 +14,10 @@ note: calling this operator moves the left-hand side | LL | fn not(self) -> Self::Output; | ^^^^ +help: consider cloning the value if the performance cost is acceptable + | +LL | !x.clone(); + | ++++++++ help: consider further restricting this bound | LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) { diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 28ae1c0688c8e..e6964a1984238 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -28,6 +28,14 @@ LL | drop_unsized(y); ... LL | println!("{}", &y); | ^^ value borrowed here after move + | +note: consider changing this parameter type in `drop_unsized` to borrow instead if ownering the value isn't necessary + --> $DIR/borrow-after-move.rs:14:31 + | +LL | fn drop_unsized<T: ?Sized>(_: T) {} + | ------------ ^ this type parameter takes ownership of the value + | | + | in this function error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:31:24 @@ -66,6 +74,11 @@ LL | x.foo(); | - value moved here LL | println!("{}", &x); | ^^ value borrowed here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | x.clone().foo(); + | ++++++++ error: aborting due to 5 previous errors; 1 warning emitted diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index dfae6cc75d9c6..7d7586b0a0bc0 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -16,6 +16,14 @@ LL | drop_unsized(y); | - value moved here LL | drop_unsized(y); | ^ value used here after move + | +note: consider changing this parameter type in `drop_unsized` to borrow instead if ownering the value isn't necessary + --> $DIR/double-move.rs:14:31 + | +LL | fn drop_unsized<T: ?Sized>(_: T) {} + | ------------ ^ this type parameter takes ownership of the value + | | + | in this function error[E0382]: use of moved value: `x` --> $DIR/double-move.rs:27:22 diff --git a/src/test/ui/use/use-after-move-based-on-type.stderr b/src/test/ui/use/use-after-move-based-on-type.stderr index 445f14d65e3ce..7b4d2454994d7 100644 --- a/src/test/ui/use/use-after-move-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-based-on-type.stderr @@ -9,6 +9,10 @@ LL | println!("{}", x); | ^ value borrowed here after move | = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = x.clone(); + | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index 26804216d9da7..a671434a30394 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -9,6 +9,14 @@ LL | l.push(n); LL | LL | let x = n.to_string(); | ^^^^^^^^^^^^^ value borrowed here after move + | +note: consider changing this parameter type in `push` to borrow instead if ownering the value isn't necessary + --> $DIR/use-after-move-implicity-coerced-object.rs:17:27 + | +LL | fn push(&mut self, n: Box<dyn ToString + 'static>) { + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this type parameter takes ownership of the value + | | + | in this method error: aborting due to previous error From fface0c29f3bbd7d83a96028f157748d62e09086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 09:19:03 -0700 Subject: [PATCH 20/38] Do not suggest `ref` multiple times for the same binding --- .../rustc_borrowck/src/diagnostics/conflict_errors.rs | 4 +++- ...fter-at-or-patterns-slice-patterns-box-patterns.stderr | 8 -------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b5dbf4dac4f24..29a40a669824e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -171,6 +171,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut is_loop_move = false; let mut in_pattern = false; + let mut seen_spans = FxHashSet::default(); for move_site in &move_site_vec { let move_out = self.move_data.moves[(*move_site).moi]; @@ -320,7 +321,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.suggest_cloning(&mut err, ty, move_span); } } - if let Some(pat) = finder.pat { + if let Some(pat) = finder.pat && !seen_spans.contains(&pat.span) { in_pattern = true; err.span_suggestion_verbose( pat.span.shrink_to_lo(), @@ -328,6 +329,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "ref ".to_string(), Applicability::MachineApplicable, ); + seen_spans.insert(pat.span); } } diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index f58672f0666be..d06b3bc1c3e60 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -88,10 +88,6 @@ help: borrow this binding in the pattern to avoid moving the value | LL | ref foo @ Some(Test::Foo | Test::Bar) => (), | +++ -help: borrow this binding in the pattern to avoid moving the value - | -LL | ref foo @ Some(Test::Foo | Test::Bar) => (), - | +++ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5 @@ -148,10 +144,6 @@ help: borrow this binding in the pattern to avoid moving the value | LL | ref a @ [.., Some(Test::Foo | Test::Bar)] => (), | +++ -help: borrow this binding in the pattern to avoid moving the value - | -LL | ref a @ [.., Some(Test::Foo | Test::Bar)] => (), - | +++ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5 From cca960dd686819b073a85e66bc7fd259a990a538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 09:19:23 -0700 Subject: [PATCH 21/38] Fix clippy code --- .../clippy/clippy_lints/src/suspicious_operation_groupings.rs | 2 +- src/tools/clippy/clippy_utils/src/ast_utils.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 78e83880e1a61..e111c7d229151 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -582,7 +582,7 @@ fn ident_difference_expr_with_base_location( | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) | (Match(_, _), Match(_, _)) - | (Loop(_, _), Loop(_, _)) + | (Loop(_, _, _), Loop(_, _, _)) | (ForLoop(_, _, _, _), ForLoop(_, _, _, _)) | (While(_, _, _), While(_, _, _)) | (If(_, _, _), If(_, _, _)) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 23aed4b5ba2f4..96e4643631b64 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -163,7 +163,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => { eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) }, - (Loop(lt, ll), Loop(rt, rl)) => eq_label(ll, rl) && eq_block(lt, rt), + (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt), (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r), From 242dd83e700bf88c33b1a9b6e65b567d3b37a2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 11:06:25 -0700 Subject: [PATCH 22/38] Use `type_implements_trait` --- .../src/diagnostics/conflict_errors.rs | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 29a40a669824e..4df3b0c19ee95 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -720,28 +720,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) { let tcx = self.infcx.tcx; - // Try to find predicates on *generic params* that would allow copying `ty` let infcx = tcx.infer_ctxt().build(); - let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx); - - let clone_did = infcx.tcx.lang_items().clone_trait().unwrap(); - let cause = ObligationCause::new( - span, - self.mir_hir_id(), - rustc_infer::traits::ObligationCauseCode::MiscObligation, - ); - fulfill_cx.register_bound( - &infcx, - self.param_env, - // Erase any region vids from the type, which may not be resolved - infcx.tcx.erase_regions(ty), - clone_did, - cause, - ); - // Select all, including ambiguous predicates - let errors = fulfill_cx.select_all_or_error(&infcx); - if errors.is_empty() { + let clone_did = tcx.lang_items().clone_trait().unwrap(); + let params = ty::List::empty(); + let ty = tcx.erase_regions(ty); + let env = self.param_env; + if infcx.type_implements_trait(clone_did, ty, params, env).must_apply_modulo_regions() { err.span_suggestion_verbose( span.shrink_to_hi(), "consider cloning the value if the performance cost is acceptable", From e88009b6aa3f7e01eea95e8040cd28ae792d8194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 11:52:26 -0700 Subject: [PATCH 23/38] Extract suggestion logic to its own method --- .../src/diagnostics/conflict_errors.rs | 296 +++++++++--------- 1 file changed, 156 insertions(+), 140 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 4df3b0c19ee95..aa29adca2f6b7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -192,146 +192,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_loop_move = true; } - struct ExpressionFinder<'hir> { - expr_span: Span, - expr: Option<&'hir hir::Expr<'hir>>, - pat: Option<&'hir hir::Pat<'hir>>, - } - impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { - if e.span == self.expr_span { - self.expr = Some(e); - } - hir::intravisit::walk_expr(self, e); - } - fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) { - if p.span == self.expr_span { - self.pat = Some(p); - } - if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, _) = p.kind - && i.span == self.expr_span - { - self.pat = Some(p); - } - hir::intravisit::walk_pat(self, p); - } - } - - let hir = self.infcx.tcx.hir(); - if let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_, _, body_id), - .. - })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id())) - && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) - { - let place = &self.move_data.move_paths[mpi].place; - let span = place.as_local() - .map(|local| self.body.local_decls[local].source_info.span); - let mut finder = ExpressionFinder { - expr_span: move_span, - expr: None, - pat: None, - }; - finder.visit_expr(expr); - if let Some(span) = span && let Some(expr) = finder.expr { - for (_, expr) in hir.parent_iter(expr.hir_id) { - if let hir::Node::Expr(expr) = expr { - if expr.span.contains(span) { - // If the let binding occurs within the same loop, then that - // loop isn't relevant, like in the following, the outermost `loop` - // doesn't play into `x` being moved. - // ``` - // loop { - // let x = String::new(); - // loop { - // foo(x); - // } - // } - // ``` - break; - } - if let hir::ExprKind::Loop(.., loop_span) = expr.kind { - err.span_label(loop_span, "inside of this loop"); - } - } - } - let typeck = self.infcx.tcx.typeck(self.mir_def_id()); - let hir_id = hir.get_parent_node(expr.hir_id); - if let Some(parent) = hir.find(hir_id) { - if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind - && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) - && let Some(def_id) = def_id.as_local() - && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) - && let Some(fn_sig) = node.fn_sig() - && let Some(ident) = node.ident() - && let Some(pos) = args.iter() - .position(|arg| arg.hir_id == expr.hir_id) - && let Some(arg) = fn_sig.decl.inputs.get(pos + 1) - { - let mut span: MultiSpan = arg.span.into(); - span.push_span_label( - arg.span, - "this type parameter takes ownership of the value".to_string(), - ); - span.push_span_label( - ident.span, - "in this method".to_string(), - ); - err.span_note( - span, - format!( - "consider changing this parameter type in `{}` to borrow \ - instead if ownering the value isn't necessary", - ident, - ), - ); - } - if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::Call(call, args) = parent_expr.kind - && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() - && let Some(def_id) = def_id.as_local() - && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) - && let Some(fn_sig) = node.fn_sig() - && let Some(ident) = node.ident() - && let Some(pos) = args.iter() - .position(|arg| arg.hir_id == expr.hir_id) - && let Some(arg) = fn_sig.decl.inputs.get(pos) - { - let mut span: MultiSpan = arg.span.into(); - span.push_span_label( - arg.span, - "this type parameter takes ownership of the value".to_string(), - ); - span.push_span_label( - ident.span, - "in this function".to_string(), - ); - err.span_note( - span, - format!( - "consider changing this parameter type in `{}` to borrow \ - instead if ownering the value isn't necessary", - ident, - ), - ); - } - let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.body, self.infcx.tcx).ty; - self.suggest_cloning(&mut err, ty, move_span); - } - } - if let Some(pat) = finder.pat && !seen_spans.contains(&pat.span) { - in_pattern = true; - err.span_suggestion_verbose( - pat.span.shrink_to_lo(), - "borrow this binding in the pattern to avoid moving the value", - "ref ".to_string(), - Applicability::MachineApplicable, - ); - seen_spans.insert(pat.span); - } - } + self.suggest_ref_or_clone( + mpi, + move_span, + &mut err, + &mut seen_spans, + &mut in_pattern, + ); self.explain_captures( &mut err, @@ -440,6 +307,155 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + fn suggest_ref_or_clone( + &mut self, + mpi: MovePathIndex, + move_span: Span, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + seen_spans: &mut FxHashSet<Span>, + in_pattern: &mut bool, + ) { + struct ExpressionFinder<'hir> { + expr_span: Span, + expr: Option<&'hir hir::Expr<'hir>>, + pat: Option<&'hir hir::Pat<'hir>>, + } + impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { + if e.span == self.expr_span { + self.expr = Some(e); + } + hir::intravisit::walk_expr(self, e); + } + fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) { + if p.span == self.expr_span { + self.pat = Some(p); + } + if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, _) = p.kind + && i.span == self.expr_span + { + self.pat = Some(p); + } + hir::intravisit::walk_pat(self, p); + } + } + let hir = self.infcx.tcx.hir(); + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_, _, body_id), + .. + })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id())) + && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) + { + let place = &self.move_data.move_paths[mpi].place; + let span = place.as_local() + .map(|local| self.body.local_decls[local].source_info.span); + let mut finder = ExpressionFinder { + expr_span: move_span, + expr: None, + pat: None, + }; + finder.visit_expr(expr); + if let Some(span) = span && let Some(expr) = finder.expr { + for (_, expr) in hir.parent_iter(expr.hir_id) { + if let hir::Node::Expr(expr) = expr { + if expr.span.contains(span) { + // If the let binding occurs within the same loop, then that + // loop isn't relevant, like in the following, the outermost `loop` + // doesn't play into `x` being moved. + // ``` + // loop { + // let x = String::new(); + // loop { + // foo(x); + // } + // } + // ``` + break; + } + if let hir::ExprKind::Loop(.., loop_span) = expr.kind { + err.span_label(loop_span, "inside of this loop"); + } + } + } + let typeck = self.infcx.tcx.typeck(self.mir_def_id()); + let hir_id = hir.get_parent_node(expr.hir_id); + if let Some(parent) = hir.find(hir_id) { + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind + && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) + && let Some(def_id) = def_id.as_local() + && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) + && let Some(fn_sig) = node.fn_sig() + && let Some(ident) = node.ident() + && let Some(pos) = args.iter() + .position(|arg| arg.hir_id == expr.hir_id) + && let Some(arg) = fn_sig.decl.inputs.get(pos + 1) + { + let mut span: MultiSpan = arg.span.into(); + span.push_span_label( + arg.span, + "this type parameter takes ownership of the value".to_string(), + ); + span.push_span_label( + ident.span, + "in this method".to_string(), + ); + err.span_note( + span, + format!( + "consider changing this parameter type in `{}` to borrow instead \ + if ownering the value isn't necessary", + ident, + ), + ); + } + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::Call(call, args) = parent_expr.kind + && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() + && let Some(def_id) = def_id.as_local() + && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) + && let Some(fn_sig) = node.fn_sig() + && let Some(ident) = node.ident() + && let Some(pos) = args.iter() + .position(|arg| arg.hir_id == expr.hir_id) + && let Some(arg) = fn_sig.decl.inputs.get(pos) + { + let mut span: MultiSpan = arg.span.into(); + span.push_span_label( + arg.span, + "this type parameter takes ownership of the value".to_string(), + ); + span.push_span_label( + ident.span, + "in this function".to_string(), + ); + err.span_note( + span, + format!( + "consider changing this parameter type in `{}` to borrow instead \ + if ownering the value isn't necessary", + ident, + ), + ); + } + let place = &self.move_data.move_paths[mpi].place; + let ty = place.ty(self.body, self.infcx.tcx).ty; + self.suggest_cloning(err, ty, move_span); + } + } + if let Some(pat) = finder.pat && !seen_spans.contains(&pat.span) { + *in_pattern = true; + err.span_suggestion_verbose( + pat.span.shrink_to_lo(), + "borrow this binding in the pattern to avoid moving the value", + "ref ".to_string(), + Applicability::MachineApplicable, + ); + seen_spans.insert(pat.span); + } + } + } + fn report_use_of_uninitialized( &self, mpi: MovePathIndex, From 0994f8d9b29af9c94ec0982906e6c373c755ddec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 12:26:59 -0700 Subject: [PATCH 24/38] Remove logic duplication --- .../src/diagnostics/conflict_errors.rs | 51 +++++++------------ .../borrowck-consume-unsize-vec.stderr | 2 +- .../borrowck-consume-upcast-box.stderr | 2 +- .../ui/borrowck/mut-borrow-in-loop-2.stderr | 2 +- .../ui/liveness/liveness-move-call-arg.stderr | 2 +- .../liveness/liveness-use-after-send.stderr | 2 +- .../borrow-closures-instead-of-move.stderr | 6 +-- .../ui/moves/move-guard-same-consts.stderr | 2 +- src/test/ui/moves/move-in-guard-1.stderr | 2 +- src/test/ui/moves/move-in-guard-2.stderr | 2 +- .../ui/moves/moves-based-on-type-exprs.stderr | 2 +- .../ui/union/union-move.mirunsafeck.stderr | 4 +- .../ui/union/union-move.thirunsafeck.stderr | 4 +- .../unsized-locals/borrow-after-move.stderr | 2 +- src/test/ui/unsized-locals/double-move.stderr | 2 +- ...after-move-implicity-coerced-object.stderr | 2 +- 16 files changed, 37 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index aa29adca2f6b7..1831e1a960cf3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -380,61 +380,46 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let typeck = self.infcx.tcx.typeck(self.mir_def_id()); let hir_id = hir.get_parent_node(expr.hir_id); if let Some(parent) = hir.find(hir_id) { - if let hir::Node::Expr(parent_expr) = parent + let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) - && let Some(def_id) = def_id.as_local() - && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) - && let Some(fn_sig) = node.fn_sig() - && let Some(ident) = node.ident() - && let Some(pos) = args.iter() - .position(|arg| arg.hir_id == expr.hir_id) - && let Some(arg) = fn_sig.decl.inputs.get(pos + 1) { - let mut span: MultiSpan = arg.span.into(); - span.push_span_label( - arg.span, - "this type parameter takes ownership of the value".to_string(), - ); - span.push_span_label( - ident.span, - "in this method".to_string(), - ); - err.span_note( - span, - format!( - "consider changing this parameter type in `{}` to borrow instead \ - if ownering the value isn't necessary", - ident, - ), - ); - } - if let hir::Node::Expr(parent_expr) = parent + (def_id.as_local(), args, 1) + } else if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::Call(call, args) = parent_expr.kind && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() - && let Some(def_id) = def_id.as_local() + { + (def_id.as_local(), args, 0) + } else { + (None, &[][..], 0) + }; + if let Some(def_id) = def_id && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) && let Some(fn_sig) = node.fn_sig() && let Some(ident) = node.ident() && let Some(pos) = args.iter() .position(|arg| arg.hir_id == expr.hir_id) - && let Some(arg) = fn_sig.decl.inputs.get(pos) + && let Some(arg) = fn_sig.decl.inputs.get(pos + offset) { let mut span: MultiSpan = arg.span.into(); span.push_span_label( arg.span, "this type parameter takes ownership of the value".to_string(), ); + let descr = match node.fn_kind() { + Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", + Some(hir::intravisit::FnKind::Method(..)) => "method", + Some(hir::intravisit::FnKind::Closure) => "closure", + }; span.push_span_label( ident.span, - "in this function".to_string(), + format!("in this {descr}"), ); err.span_note( span, format!( - "consider changing this parameter type in `{}` to borrow instead \ - if ownering the value isn't necessary", - ident, + "consider changing this parameter type in {descr} `{ident}` to \ + borrow instead if ownering the value isn't necessary", ), ); } diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr index 00bb13caebdb5..cfaa8c08df836 100644 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr +++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -8,7 +8,7 @@ LL | consume(b); LL | consume(b); | ^ value used here after move | -note: consider changing this parameter type in `consume` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `consume` to borrow instead if ownering the value isn't necessary --> $DIR/borrowck-consume-unsize-vec.rs:3:15 | LL | fn consume(_: Box<[i32]>) { diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr index 103f45155d7ba..c73d1df971acf 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -8,7 +8,7 @@ LL | consume(b); LL | consume(b); | ^ value used here after move | -note: consider changing this parameter type in `consume` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `consume` to borrow instead if ownering the value isn't necessary --> $DIR/borrowck-consume-upcast-box.rs:5:15 | LL | fn consume(_: Box<dyn Foo>) { diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr index eaf53868014fa..4f287d3a735e1 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr +++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr @@ -8,7 +8,7 @@ LL | for _ in 0..3 { LL | Other::handle(value); | ^^^^^ value moved here, in previous iteration of loop | -note: consider changing this parameter type in `handle` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `handle` to borrow instead if ownering the value isn't necessary --> $DIR/mut-borrow-in-loop-2.rs:9:22 | LL | fn handle(value: T) -> Self; diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index bd45aa5345885..4a869cdce4a17 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -9,7 +9,7 @@ LL | loop { LL | take(x); | ^ value moved here, in previous iteration of loop | -note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary --> $DIR/liveness-move-call-arg.rs:1:13 | LL | fn take(_x: Box<isize>) {} diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr index c407827d32050..cf4aa8fc9c414 100644 --- a/src/test/ui/liveness/liveness-use-after-send.stderr +++ b/src/test/ui/liveness/liveness-use-after-send.stderr @@ -8,7 +8,7 @@ LL | send(ch, message); LL | println!("{}", message); | ^^^^^^^ value borrowed here after move | -note: consider changing this parameter type in `send` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `send` to borrow instead if ownering the value isn't necessary --> $DIR/liveness-use-after-send.rs:3:54 | LL | fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) { diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr index 11fcb1cc26381..d3f250e69b24c 100644 --- a/src/test/ui/moves/borrow-closures-instead-of-move.stderr +++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr @@ -8,7 +8,7 @@ LL | loop { LL | takes_fnonce(f); | ^ value moved here, in previous iteration of loop | -note: consider changing this parameter type in `takes_fnonce` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `takes_fnonce` to borrow instead if ownering the value isn't necessary --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} @@ -32,7 +32,7 @@ LL | takes_fnonce(m); LL | takes_fnonce(m); | ^ value used here after move | -note: consider changing this parameter type in `takes_fnonce` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `takes_fnonce` to borrow instead if ownering the value isn't necessary --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} @@ -58,7 +58,7 @@ note: closure cannot be moved more than once as it is not `Copy` due to moving t | LL | x += 1; | ^ -note: consider changing this parameter type in `takes_fnonce` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `takes_fnonce` to borrow instead if ownering the value isn't necessary --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 04a41b9ce2623..687e8497dc6e8 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -9,7 +9,7 @@ LL | (1, 2) if take(x) => (), LL | (1, 2) if take(x) => (), | ^ value used here after move | -note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary --> $DIR/move-guard-same-consts.rs:25:15 | LL | fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index d435426f2ec97..a21dca7f16ee5 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -9,7 +9,7 @@ LL | (1, _) if take(x) => (), LL | (_, 2) if take(x) => (), | ^ value used here after move | -note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary --> $DIR/move-in-guard-1.rs:15:15 | LL | fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index 0f4895c2ac132..5277a812a44c8 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -7,7 +7,7 @@ LL | let x: Box<_> = Box::new(1); LL | (_, 2) if take(x) => (), | ^ value used here after move | -note: consider changing this parameter type in `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary --> $DIR/move-in-guard-2.rs:13:15 | LL | fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 78138d214f9a4..37fb40ffe78c0 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -108,7 +108,7 @@ LL | _ if guard(x) => 10, LL | touch(&x); | ^^ value borrowed here after move | -note: consider changing this parameter type in `guard` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `guard` to borrow instead if ownering the value isn't necessary --> $DIR/moves-based-on-type-exprs.rs:6:14 | LL | fn guard(_s: String) -> bool {panic!()} diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr index 91f2eaad944eb..46b7be440e04e 100644 --- a/src/test/ui/union/union-move.mirunsafeck.stderr +++ b/src/test/ui/union/union-move.mirunsafeck.stderr @@ -9,7 +9,7 @@ LL | move_out(x.f1_nocopy); LL | move_out(x.f2_nocopy); | ^^^^^^^^^^^ value used here after move | -note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} @@ -28,7 +28,7 @@ LL | move_out(x.f2_nocopy); LL | move_out(x.f3_copy); | ^^^^^^^^^ value used here after move | -note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr index 91f2eaad944eb..46b7be440e04e 100644 --- a/src/test/ui/union/union-move.thirunsafeck.stderr +++ b/src/test/ui/union/union-move.thirunsafeck.stderr @@ -9,7 +9,7 @@ LL | move_out(x.f1_nocopy); LL | move_out(x.f2_nocopy); | ^^^^^^^^^^^ value used here after move | -note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} @@ -28,7 +28,7 @@ LL | move_out(x.f2_nocopy); LL | move_out(x.f3_copy); | ^^^^^^^^^ value used here after move | -note: consider changing this parameter type in `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index e6964a1984238..f63684407ecb2 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -29,7 +29,7 @@ LL | drop_unsized(y); LL | println!("{}", &y); | ^^ value borrowed here after move | -note: consider changing this parameter type in `drop_unsized` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `drop_unsized` to borrow instead if ownering the value isn't necessary --> $DIR/borrow-after-move.rs:14:31 | LL | fn drop_unsized<T: ?Sized>(_: T) {} diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 7d7586b0a0bc0..b883067427f43 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -17,7 +17,7 @@ LL | drop_unsized(y); LL | drop_unsized(y); | ^ value used here after move | -note: consider changing this parameter type in `drop_unsized` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `drop_unsized` to borrow instead if ownering the value isn't necessary --> $DIR/double-move.rs:14:31 | LL | fn drop_unsized<T: ?Sized>(_: T) {} diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index a671434a30394..7d94aa216828c 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -10,7 +10,7 @@ LL | LL | let x = n.to_string(); | ^^^^^^^^^^^^^ value borrowed here after move | -note: consider changing this parameter type in `push` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in method `push` to borrow instead if ownering the value isn't necessary --> $DIR/use-after-move-implicity-coerced-object.rs:17:27 | LL | fn push(&mut self, n: Box<dyn ToString + 'static>) { From 4918d4f668668f3a6d9af8b1135477bd4cfc83e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 13:51:44 -0700 Subject: [PATCH 25/38] Tweak output in for loops Do not suggest `.clone()` as we already suggest borrowing the iterated value. --- .../src/diagnostics/conflict_errors.rs | 15 ++++++++++++--- src/test/ui/issues/issue-61108.stderr | 4 ---- src/test/ui/issues/issue-64559.stderr | 4 ---- src/test/ui/moves/move-fn-self-receiver.stderr | 4 ---- .../ui/suggestions/borrow-for-loop-head.stderr | 4 ---- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1831e1a960cf3..a9416cae75f4e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -7,6 +7,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; +// use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LoopSource::ForLoop}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; @@ -397,8 +398,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) && let Some(fn_sig) = node.fn_sig() && let Some(ident) = node.ident() - && let Some(pos) = args.iter() - .position(|arg| arg.hir_id == expr.hir_id) + && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && let Some(arg) = fn_sig.decl.inputs.get(pos + offset) { let mut span: MultiSpan = arg.span.into(); @@ -425,7 +425,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } let place = &self.move_data.move_paths[mpi].place; let ty = place.ty(self.body, self.infcx.tcx).ty; - self.suggest_cloning(err, ty, move_span); + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind + && let hir::ExprKind::Path( + hir::QPath::LangItem(hir::LangItem::IntoIterIntoIter, _, _) + ) = call_expr.kind + { + // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. + } else { + self.suggest_cloning(err, ty, move_span); + } } } if let Some(pat) = finder.pat && !seen_spans.contains(&pat.span) { diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index 0f6f30531b332..e5b671d7b7ab0 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -14,10 +14,6 @@ note: this function takes ownership of the receiver `self`, which moves `bad_let | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ -help: consider cloning the value if the performance cost is acceptable - | -LL | for l in bad_letters.clone() { - | ++++++++ help: consider iterating over a slice of the `Vec<char>`'s content to avoid moving into the `for` loop | LL | for l in &bad_letters { diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index 5c04cefa5304b..ef178bbd15538 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -15,10 +15,6 @@ note: this function takes ownership of the receiver `self`, which moves `orig` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ -help: consider cloning the value if the performance cost is acceptable - | -LL | for _val in orig.clone() {} - | ++++++++ help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop | LL | for _val in &orig {} diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr index b331b10a3b79e..c13dc58826eb8 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -127,10 +127,6 @@ LL | for _val in implicit_into_iter {} LL | implicit_into_iter; | ^^^^^^^^^^^^^^^^^^ value used here after move | -help: consider cloning the value if the performance cost is acceptable - | -LL | for _val in implicit_into_iter.clone() {} - | ++++++++ help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop | LL | for _val in &implicit_into_iter {} diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr index 7cd411dde6c21..0cc8994fe1f2d 100644 --- a/src/test/ui/suggestions/borrow-for-loop-head.stderr +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -21,10 +21,6 @@ note: this function takes ownership of the receiver `self`, which moves `a` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ -help: consider cloning the value if the performance cost is acceptable - | -LL | for j in a.clone() { - | ++++++++ help: consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop | LL | for j in &a { From 33a6dc9ca943ab8b41f79d0e26fcc31518327178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 14:10:08 -0700 Subject: [PATCH 26/38] Fix wording --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 2 +- src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr | 2 +- src/test/ui/borrowck/borrowck-consume-upcast-box.stderr | 2 +- src/test/ui/borrowck/mut-borrow-in-loop-2.stderr | 2 +- src/test/ui/liveness/liveness-move-call-arg.stderr | 2 +- src/test/ui/liveness/liveness-use-after-send.stderr | 2 +- src/test/ui/moves/borrow-closures-instead-of-move.stderr | 6 +++--- src/test/ui/moves/move-guard-same-consts.stderr | 2 +- src/test/ui/moves/move-in-guard-1.stderr | 2 +- src/test/ui/moves/move-in-guard-2.stderr | 2 +- src/test/ui/moves/moves-based-on-type-exprs.stderr | 2 +- src/test/ui/union/union-move.mirunsafeck.stderr | 4 ++-- src/test/ui/union/union-move.thirunsafeck.stderr | 4 ++-- src/test/ui/unsized-locals/borrow-after-move.stderr | 2 +- src/test/ui/unsized-locals/double-move.stderr | 2 +- .../ui/use/use-after-move-implicity-coerced-object.stderr | 2 +- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a9416cae75f4e..544296852fc12 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -404,7 +404,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut span: MultiSpan = arg.span.into(); span.push_span_label( arg.span, - "this type parameter takes ownership of the value".to_string(), + "this parameter takes ownership of the value".to_string(), ); let descr = match node.fn_kind() { Some(hir::intravisit::FnKind::ItemFn(..)) | None => "function", diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr index cfaa8c08df836..c25337c0c6c63 100644 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr +++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -12,7 +12,7 @@ note: consider changing this parameter type in function `consume` to borrow inst --> $DIR/borrowck-consume-unsize-vec.rs:3:15 | LL | fn consume(_: Box<[i32]>) { - | ------- ^^^^^^^^^^ this type parameter takes ownership of the value + | ------- ^^^^^^^^^^ this parameter takes ownership of the value | | | in this function help: consider cloning the value if the performance cost is acceptable diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr index c73d1df971acf..49d85cd5fa2a7 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -12,7 +12,7 @@ note: consider changing this parameter type in function `consume` to borrow inst --> $DIR/borrowck-consume-upcast-box.rs:5:15 | LL | fn consume(_: Box<dyn Foo>) { - | ------- ^^^^^^^^^^^^ this type parameter takes ownership of the value + | ------- ^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr index 4f287d3a735e1..b441244cdfdea 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr +++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr @@ -12,7 +12,7 @@ note: consider changing this parameter type in function `handle` to borrow inste --> $DIR/mut-borrow-in-loop-2.rs:9:22 | LL | fn handle(value: T) -> Self; - | ------ ^ this type parameter takes ownership of the value + | ------ ^ this parameter takes ownership of the value | | | in this function help: consider creating a fresh reborrow of `value` here diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index 4a869cdce4a17..5b5ac65113fdd 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -13,7 +13,7 @@ note: consider changing this parameter type in function `take` to borrow instead --> $DIR/liveness-move-call-arg.rs:1:13 | LL | fn take(_x: Box<isize>) {} - | ---- ^^^^^^^^^^ this type parameter takes ownership of the value + | ---- ^^^^^^^^^^ this parameter takes ownership of the value | | | in this function help: consider cloning the value if the performance cost is acceptable diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr index cf4aa8fc9c414..3dbe5ac517e43 100644 --- a/src/test/ui/liveness/liveness-use-after-send.stderr +++ b/src/test/ui/liveness/liveness-use-after-send.stderr @@ -12,7 +12,7 @@ note: consider changing this parameter type in function `send` to borrow instead --> $DIR/liveness-use-after-send.rs:3:54 | LL | fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) { - | ---- in this function ^ this type parameter takes ownership of the value + | ---- in this function ^ this parameter takes ownership of the value = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider cloning the value if the performance cost is acceptable | diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr index d3f250e69b24c..b68552220397c 100644 --- a/src/test/ui/moves/borrow-closures-instead-of-move.stderr +++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr @@ -12,7 +12,7 @@ note: consider changing this parameter type in function `takes_fnonce` to borrow --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} - | ------------ ^^^^^^^^^^^^^ this type parameter takes ownership of the value + | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function help: consider borrowing `f` @@ -36,7 +36,7 @@ note: consider changing this parameter type in function `takes_fnonce` to borrow --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} - | ------------ ^^^^^^^^^^^^^ this type parameter takes ownership of the value + | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function help: consider mutably borrowing `m` @@ -62,7 +62,7 @@ note: consider changing this parameter type in function `takes_fnonce` to borrow --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} - | ------------ ^^^^^^^^^^^^^ this type parameter takes ownership of the value + | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function help: consider mutably borrowing `closure` diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 687e8497dc6e8..440a908a3c662 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -13,7 +13,7 @@ note: consider changing this parameter type in function `take` to borrow instead --> $DIR/move-guard-same-consts.rs:25:15 | LL | fn take<T>(_: T) -> bool { false } - | ---- ^ this type parameter takes ownership of the value + | ---- ^ this parameter takes ownership of the value | | | in this function help: consider cloning the value if the performance cost is acceptable diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index a21dca7f16ee5..e054f31349a6c 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -13,7 +13,7 @@ note: consider changing this parameter type in function `take` to borrow instead --> $DIR/move-in-guard-1.rs:15:15 | LL | fn take<T>(_: T) -> bool { false } - | ---- ^ this type parameter takes ownership of the value + | ---- ^ this parameter takes ownership of the value | | | in this function help: consider cloning the value if the performance cost is acceptable diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index 5277a812a44c8..49267c2763159 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -11,7 +11,7 @@ note: consider changing this parameter type in function `take` to borrow instead --> $DIR/move-in-guard-2.rs:13:15 | LL | fn take<T>(_: T) -> bool { false } - | ---- ^ this type parameter takes ownership of the value + | ---- ^ this parameter takes ownership of the value | | | in this function help: consider cloning the value if the performance cost is acceptable diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 37fb40ffe78c0..6efda8c5e8366 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -112,7 +112,7 @@ note: consider changing this parameter type in function `guard` to borrow instea --> $DIR/moves-based-on-type-exprs.rs:6:14 | LL | fn guard(_s: String) -> bool {panic!()} - | ----- ^^^^^^ this type parameter takes ownership of the value + | ----- ^^^^^^ this parameter takes ownership of the value | | | in this function help: consider cloning the value if the performance cost is acceptable diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr index 46b7be440e04e..c695282fbb0d3 100644 --- a/src/test/ui/union/union-move.mirunsafeck.stderr +++ b/src/test/ui/union/union-move.mirunsafeck.stderr @@ -13,7 +13,7 @@ note: consider changing this parameter type in function `move_out` to borrow ins --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} - | -------- ^ this type parameter takes ownership of the value + | -------- ^ this parameter takes ownership of the value | | | in this function @@ -32,7 +32,7 @@ note: consider changing this parameter type in function `move_out` to borrow ins --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} - | -------- ^ this type parameter takes ownership of the value + | -------- ^ this parameter takes ownership of the value | | | in this function diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr index 46b7be440e04e..c695282fbb0d3 100644 --- a/src/test/ui/union/union-move.thirunsafeck.stderr +++ b/src/test/ui/union/union-move.thirunsafeck.stderr @@ -13,7 +13,7 @@ note: consider changing this parameter type in function `move_out` to borrow ins --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} - | -------- ^ this type parameter takes ownership of the value + | -------- ^ this parameter takes ownership of the value | | | in this function @@ -32,7 +32,7 @@ note: consider changing this parameter type in function `move_out` to borrow ins --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} - | -------- ^ this type parameter takes ownership of the value + | -------- ^ this parameter takes ownership of the value | | | in this function diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index f63684407ecb2..e11c398e8d030 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -33,7 +33,7 @@ note: consider changing this parameter type in function `drop_unsized` to borrow --> $DIR/borrow-after-move.rs:14:31 | LL | fn drop_unsized<T: ?Sized>(_: T) {} - | ------------ ^ this type parameter takes ownership of the value + | ------------ ^ this parameter takes ownership of the value | | | in this function diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index b883067427f43..84192e7509896 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -21,7 +21,7 @@ note: consider changing this parameter type in function `drop_unsized` to borrow --> $DIR/double-move.rs:14:31 | LL | fn drop_unsized<T: ?Sized>(_: T) {} - | ------------ ^ this type parameter takes ownership of the value + | ------------ ^ this parameter takes ownership of the value | | | in this function diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index 7d94aa216828c..395bb4019fd61 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -14,7 +14,7 @@ note: consider changing this parameter type in method `push` to borrow instead i --> $DIR/use-after-move-implicity-coerced-object.rs:17:27 | LL | fn push(&mut self, n: Box<dyn ToString + 'static>) { - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this type parameter takes ownership of the value + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this method From 6f77be4dbc4d286551d97e4a31782b35d88b12db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 14:22:35 -0700 Subject: [PATCH 27/38] Fix rustfmt --- src/tools/rustfmt/src/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index aba1c484bf1dd..d33faa5b92a3f 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -660,7 +660,7 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow< ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => { Some(ControlFlow::new_for(pat, cond, block, label, expr.span)) } - ast::ExprKind::Loop(ref block, label) => { + ast::ExprKind::Loop(ref block, label, _) => { Some(ControlFlow::new_loop(block, label, expr.span)) } ast::ExprKind::While(ref cond, ref block, label) => { From a930d447b438088bf876d65d5c282adb9ef2c979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 15:08:38 -0700 Subject: [PATCH 28/38] Tweak output to account for alternative bindings in the same pattern --- .../src/diagnostics/conflict_errors.rs | 39 ++++++++----------- ...atterns-slice-patterns-box-patterns.stderr | 10 +---- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 544296852fc12..bfb42f733ffda 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -193,26 +193,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { is_loop_move = true; } - self.suggest_ref_or_clone( - mpi, - move_span, - &mut err, - &mut seen_spans, - &mut in_pattern, - ); + if !seen_spans.contains(&move_span) { + self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern); - self.explain_captures( - &mut err, - span, - move_span, - move_spans, - *moved_place, - partially_str, - loop_message, - move_msg, - is_loop_move, - maybe_reinitialized_locations.is_empty(), - ); + self.explain_captures( + &mut err, + span, + move_span, + move_spans, + *moved_place, + partially_str, + loop_message, + move_msg, + is_loop_move, + maybe_reinitialized_locations.is_empty(), + ); + } + seen_spans.insert(move_span); } use_spans.var_path_only_subdiag(&mut err, desired_action); @@ -313,7 +310,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { mpi: MovePathIndex, move_span: Span, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, - seen_spans: &mut FxHashSet<Span>, in_pattern: &mut bool, ) { struct ExpressionFinder<'hir> { @@ -437,7 +433,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - if let Some(pat) = finder.pat && !seen_spans.contains(&pat.span) { + if let Some(pat) = finder.pat { *in_pattern = true; err.span_suggestion_verbose( pat.span.shrink_to_lo(), @@ -445,7 +441,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "ref ".to_string(), Applicability::MachineApplicable, ); - seen_spans.insert(pat.span); } } } diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index d06b3bc1c3e60..50eee1049db6e 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -76,10 +76,7 @@ LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) { | - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait LL | match x { LL | foo @ Some(Test::Foo | Test::Bar) => (), - | --- - | | - | value moved here - | value moved here + | --- value moved here ... LL | &x; | ^^ value borrowed here after move @@ -132,10 +129,7 @@ LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) | - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait LL | match x { LL | a @ [.., Some(Test::Foo | Test::Bar)] => (), - | - - | | - | value moved here - | value moved here + | - value moved here ... LL | &x; | ^^ value borrowed here after move From 5bf1413eaa0b9d1a5bfc52ed290e5e5b33a6be2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 15:10:29 -0700 Subject: [PATCH 29/38] Fix rebase --- src/test/ui/track-diagnostics/track2.stderr | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/ui/track-diagnostics/track2.stderr b/src/test/ui/track-diagnostics/track2.stderr index 38a621da81644..53f20259a8e5f 100644 --- a/src/test/ui/track-diagnostics/track2.stderr +++ b/src/test/ui/track-diagnostics/track2.stderr @@ -7,6 +7,11 @@ LL | let _moved @ _from = String::from("foo"); | | value moved here | value used here after move -Ztrack-diagnostics: created at compiler/rustc_borrowck/src/borrowck_errors.rs:LL:CC + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let _moved @ ref _from = String::from("foo"); + | +++ error: aborting due to previous error From 95a5beb68b531b1ef7f9c3f2d91ccee9ed4ede02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Thu, 3 Nov 2022 17:01:03 -0700 Subject: [PATCH 30/38] remove spurious commented out code --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index bfb42f733ffda..b8b15fbf8cf71 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -7,7 +7,6 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; -// use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LoopSource::ForLoop}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; From 2698d245d1581579cd75f14c274d54829bb8f6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Fri, 11 Nov 2022 16:57:01 -0800 Subject: [PATCH 31/38] review comments: inline bindings and fix typo --- .../src/diagnostics/conflict_errors.rs | 14 +++++++++----- .../ui/borrowck/borrowck-consume-unsize-vec.stderr | 2 +- .../ui/borrowck/borrowck-consume-upcast-box.stderr | 2 +- src/test/ui/borrowck/mut-borrow-in-loop-2.stderr | 2 +- src/test/ui/liveness/liveness-move-call-arg.stderr | 2 +- .../ui/liveness/liveness-use-after-send.stderr | 2 +- .../moves/borrow-closures-instead-of-move.stderr | 6 +++--- src/test/ui/moves/move-guard-same-consts.stderr | 2 +- src/test/ui/moves/move-in-guard-1.stderr | 2 +- src/test/ui/moves/move-in-guard-2.stderr | 2 +- src/test/ui/moves/moves-based-on-type-exprs.stderr | 2 +- src/test/ui/union/union-move.mirunsafeck.stderr | 4 ++-- src/test/ui/union/union-move.thirunsafeck.stderr | 4 ++-- .../ui/unsized-locals/borrow-after-move.stderr | 2 +- src/test/ui/unsized-locals/double-move.stderr | 2 +- .../use-after-move-implicity-coerced-object.stderr | 2 +- 16 files changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b8b15fbf8cf71..5f1bd1405818c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -726,11 +726,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; // Try to find predicates on *generic params* that would allow copying `ty` let infcx = tcx.infer_ctxt().build(); - let clone_did = tcx.lang_items().clone_trait().unwrap(); - let params = ty::List::empty(); - let ty = tcx.erase_regions(ty); - let env = self.param_env; - if infcx.type_implements_trait(clone_did, ty, params, env).must_apply_modulo_regions() { + if infcx + .type_implements_trait( + tcx.lang_items().clone_trait().unwrap(), + tcx.erase_regions(ty), + ty::List::empty(), + self.param_env, + ) + .must_apply_modulo_regions() + { err.span_suggestion_verbose( span.shrink_to_hi(), "consider cloning the value if the performance cost is acceptable", diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr index c25337c0c6c63..d2e9497d0795c 100644 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr +++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -8,7 +8,7 @@ LL | consume(b); LL | consume(b); | ^ value used here after move | -note: consider changing this parameter type in function `consume` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary --> $DIR/borrowck-consume-unsize-vec.rs:3:15 | LL | fn consume(_: Box<[i32]>) { diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr index 49d85cd5fa2a7..ed7e883ca6392 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -8,7 +8,7 @@ LL | consume(b); LL | consume(b); | ^ value used here after move | -note: consider changing this parameter type in function `consume` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary --> $DIR/borrowck-consume-upcast-box.rs:5:15 | LL | fn consume(_: Box<dyn Foo>) { diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr index b441244cdfdea..74e7067c9afaa 100644 --- a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr +++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr @@ -8,7 +8,7 @@ LL | for _ in 0..3 { LL | Other::handle(value); | ^^^^^ value moved here, in previous iteration of loop | -note: consider changing this parameter type in function `handle` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `handle` to borrow instead if owning the value isn't necessary --> $DIR/mut-borrow-in-loop-2.rs:9:22 | LL | fn handle(value: T) -> Self; diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index 5b5ac65113fdd..d14cd6cb4e03a 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -9,7 +9,7 @@ LL | loop { LL | take(x); | ^ value moved here, in previous iteration of loop | -note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary --> $DIR/liveness-move-call-arg.rs:1:13 | LL | fn take(_x: Box<isize>) {} diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr index 3dbe5ac517e43..65d55ca8f7073 100644 --- a/src/test/ui/liveness/liveness-use-after-send.stderr +++ b/src/test/ui/liveness/liveness-use-after-send.stderr @@ -8,7 +8,7 @@ LL | send(ch, message); LL | println!("{}", message); | ^^^^^^^ value borrowed here after move | -note: consider changing this parameter type in function `send` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `send` to borrow instead if owning the value isn't necessary --> $DIR/liveness-use-after-send.rs:3:54 | LL | fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) { diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr index b68552220397c..fbeeaf646e1ee 100644 --- a/src/test/ui/moves/borrow-closures-instead-of-move.stderr +++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr @@ -8,7 +8,7 @@ LL | loop { LL | takes_fnonce(f); | ^ value moved here, in previous iteration of loop | -note: consider changing this parameter type in function `takes_fnonce` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} @@ -32,7 +32,7 @@ LL | takes_fnonce(m); LL | takes_fnonce(m); | ^ value used here after move | -note: consider changing this parameter type in function `takes_fnonce` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} @@ -58,7 +58,7 @@ note: closure cannot be moved more than once as it is not `Copy` due to moving t | LL | x += 1; | ^ -note: consider changing this parameter type in function `takes_fnonce` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary --> $DIR/borrow-closures-instead-of-move.rs:34:20 | LL | fn takes_fnonce(_: impl FnOnce()) {} diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 440a908a3c662..86e5f65248b97 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -9,7 +9,7 @@ LL | (1, 2) if take(x) => (), LL | (1, 2) if take(x) => (), | ^ value used here after move | -note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary --> $DIR/move-guard-same-consts.rs:25:15 | LL | fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index e054f31349a6c..f04cb34d7c46e 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -9,7 +9,7 @@ LL | (1, _) if take(x) => (), LL | (_, 2) if take(x) => (), | ^ value used here after move | -note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary --> $DIR/move-in-guard-1.rs:15:15 | LL | fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index 49267c2763159..26047861f55d7 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -7,7 +7,7 @@ LL | let x: Box<_> = Box::new(1); LL | (_, 2) if take(x) => (), | ^ value used here after move | -note: consider changing this parameter type in function `take` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary --> $DIR/move-in-guard-2.rs:13:15 | LL | fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 6efda8c5e8366..838b1282cb4ed 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -108,7 +108,7 @@ LL | _ if guard(x) => 10, LL | touch(&x); | ^^ value borrowed here after move | -note: consider changing this parameter type in function `guard` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `guard` to borrow instead if owning the value isn't necessary --> $DIR/moves-based-on-type-exprs.rs:6:14 | LL | fn guard(_s: String) -> bool {panic!()} diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr index c695282fbb0d3..6381ae874ba81 100644 --- a/src/test/ui/union/union-move.mirunsafeck.stderr +++ b/src/test/ui/union/union-move.mirunsafeck.stderr @@ -9,7 +9,7 @@ LL | move_out(x.f1_nocopy); LL | move_out(x.f2_nocopy); | ^^^^^^^^^^^ value used here after move | -note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} @@ -28,7 +28,7 @@ LL | move_out(x.f2_nocopy); LL | move_out(x.f3_copy); | ^^^^^^^^^ value used here after move | -note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr index c695282fbb0d3..6381ae874ba81 100644 --- a/src/test/ui/union/union-move.thirunsafeck.stderr +++ b/src/test/ui/union/union-move.thirunsafeck.stderr @@ -9,7 +9,7 @@ LL | move_out(x.f1_nocopy); LL | move_out(x.f2_nocopy); | ^^^^^^^^^^^ value used here after move | -note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} @@ -28,7 +28,7 @@ LL | move_out(x.f2_nocopy); LL | move_out(x.f3_copy); | ^^^^^^^^^ value used here after move | -note: consider changing this parameter type in function `move_out` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary --> $DIR/union-move.rs:10:19 | LL | fn move_out<T>(x: T) {} diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index e11c398e8d030..d8bffd4f9cf3e 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -29,7 +29,7 @@ LL | drop_unsized(y); LL | println!("{}", &y); | ^^ value borrowed here after move | -note: consider changing this parameter type in function `drop_unsized` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary --> $DIR/borrow-after-move.rs:14:31 | LL | fn drop_unsized<T: ?Sized>(_: T) {} diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 84192e7509896..71534818141ca 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -17,7 +17,7 @@ LL | drop_unsized(y); LL | drop_unsized(y); | ^ value used here after move | -note: consider changing this parameter type in function `drop_unsized` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary --> $DIR/double-move.rs:14:31 | LL | fn drop_unsized<T: ?Sized>(_: T) {} diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index 395bb4019fd61..dfa0c04836eb3 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -10,7 +10,7 @@ LL | LL | let x = n.to_string(); | ^^^^^^^^^^^^^ value borrowed here after move | -note: consider changing this parameter type in method `push` to borrow instead if ownering the value isn't necessary +note: consider changing this parameter type in method `push` to borrow instead if owning the value isn't necessary --> $DIR/use-after-move-implicity-coerced-object.rs:17:27 | LL | fn push(&mut self, n: Box<dyn ToString + 'static>) { From 9a39012719091caa3d4d114abcc10e4c04394924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Tue, 15 Nov 2022 09:01:20 -0800 Subject: [PATCH 32/38] Account for `x @ y` and suggest `ref x @ ref y` --- .../src/diagnostics/conflict_errors.rs | 30 ++-- .../src/thir/pattern/check_match.rs | 16 ++- ...can-live-while-the-other-survives-1.stderr | 10 ++ .../borrowck-move-and-move.stderr | 20 +-- ...t-by-move-and-ref-inverse-promotion.stderr | 5 + ...orrowck-pat-by-move-and-ref-inverse.stderr | 133 +++++++++++++++++- .../borrowck-pat-ref-mut-twice.stderr | 20 +++ .../copy-and-move-mixed.stderr | 4 +- ...inding-modes-both-sides-independent.stderr | 5 + .../ui/suggestions/ref-pattern-binding.fixed | 19 +++ .../ui/suggestions/ref-pattern-binding.rs | 19 +++ .../ui/suggestions/ref-pattern-binding.stderr | 107 ++++++++++++++ src/test/ui/track-diagnostics/track2.stderr | 4 +- 13 files changed, 362 insertions(+), 30 deletions(-) create mode 100644 src/test/ui/suggestions/ref-pattern-binding.fixed create mode 100644 src/test/ui/suggestions/ref-pattern-binding.rs create mode 100644 src/test/ui/suggestions/ref-pattern-binding.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 5f1bd1405818c..1f45baef8a805 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -315,6 +315,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { expr_span: Span, expr: Option<&'hir hir::Expr<'hir>>, pat: Option<&'hir hir::Pat<'hir>>, + parent_pat: Option<&'hir hir::Pat<'hir>>, } impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { @@ -327,10 +328,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if p.span == self.expr_span { self.pat = Some(p); } - if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, _) = p.kind - && i.span == self.expr_span - { - self.pat = Some(p); + if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, sub) = p.kind { + if i.span == self.expr_span || p.span == self.expr_span { + self.pat = Some(p); + } + // Check if we are in a situation of `ident @ ident` where we want to suggest + // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`. + if let Some(subpat) = sub && self.pat.is_none() { + self.visit_pat(subpat); + if self.pat.is_some() { + self.parent_pat = Some(p); + } + return; + } } hir::intravisit::walk_pat(self, p); } @@ -349,6 +359,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { expr_span: move_span, expr: None, pat: None, + parent_pat: None, }; finder.visit_expr(expr); if let Some(span) = span && let Some(expr) = finder.expr { @@ -414,7 +425,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span, format!( "consider changing this parameter type in {descr} `{ident}` to \ - borrow instead if ownering the value isn't necessary", + borrow instead if owning the value isn't necessary", ), ); } @@ -434,10 +445,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } if let Some(pat) = finder.pat { *in_pattern = true; - err.span_suggestion_verbose( - pat.span.shrink_to_lo(), + let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; + if let Some(pat) = finder.parent_pat { + sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string())); + } + err.multipart_suggestion_verbose( "borrow this binding in the pattern to avoid moving the value", - "ref ".to_string(), + sugg, Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 0df228a0d599a..36100ed08e321 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1044,11 +1044,19 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa name, typeck_results.node_type(pat.hir_id), ); - sess.struct_span_err(pat.span, "borrow of moved value") - .span_label(binding_span, format!("value moved into `{}` here", name)) + let mut err = sess.struct_span_err(pat.span, "borrow of moved value"); + err.span_label(binding_span, format!("value moved into `{}` here", name)) .span_label(binding_span, occurs_because) - .span_labels(conflicts_ref, "value borrowed here after move") - .emit(); + .span_labels(conflicts_ref, "value borrowed here after move"); + if pat.span.contains(binding_span) { + err.span_suggestion_verbose( + binding_span.shrink_to_lo(), + "borrow this binding in the pattern to avoid moving the value", + "ref ".to_string(), + Applicability::MachineApplicable, + ); + } + err.emit(); } return; } diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index e79e4e7dfa336..c8b45fd24d98c 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -16,6 +16,11 @@ LL | Some(_z @ ref _y) => {} | | value borrowed here after move | value moved into `_z` here | move occurs because `_z` has type `X` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | Some(ref _z @ ref _y) => {} + | +++ error: cannot move out of value because it is borrowed --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14 @@ -35,6 +40,11 @@ LL | Some(_z @ ref mut _y) => {} | | value borrowed here after move | value moved into `_z` here | move occurs because `_z` has type `X` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | Some(ref _z @ ref mut _y) => {} + | +++ error[E0382]: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index 077583dd2527c..324897151124c 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -9,8 +9,8 @@ LL | let a @ b = U; | help: borrow this binding in the pattern to avoid moving the value | -LL | let a @ ref b = U; - | +++ +LL | let ref a @ ref b = U; + | +++ +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:13:9 @@ -23,8 +23,8 @@ LL | let a @ (b, c) = (U, U); = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | let a @ (b, ref c) = (U, U); - | +++ +LL | let ref a @ (b, ref c) = (U, U); + | +++ +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:15:9 @@ -37,8 +37,8 @@ LL | let a @ (b, c) = (u(), u()); = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | let a @ (b, ref c) = (u(), u()); - | +++ +LL | let ref a @ (b, ref c) = (u(), u()); + | +++ +++ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:18:16 @@ -81,8 +81,8 @@ LL | xs @ [a, .., b] => {} = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | xs @ [a, .., ref b] => {} - | +++ +LL | ref xs @ [a, .., ref b] => {} + | +++ +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:29:9 @@ -95,8 +95,8 @@ LL | xs @ [_, ys @ .., _] => {} = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | xs @ [_, ref ys @ .., _] => {} - | +++ +LL | ref xs @ [_, ref ys @ .., _] => {} + | +++ +++ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:22:12 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index be4e81c61aa62..d6474f1b49fb0 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -7,6 +7,11 @@ LL | let a @ ref b = U; | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ ref b = U; + | +++ error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index a41ebf1931f94..389e86e646457 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -7,6 +7,11 @@ LL | let a @ ref b = U; | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ ref b = U; + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9 @@ -18,6 +23,11 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ (mut b @ ref mut c, d @ ref e) = (U, U); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14 @@ -28,6 +38,11 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | value borrowed here after move | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (ref mut b @ ref mut c, d @ ref e) = (U, U); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33 @@ -38,6 +53,11 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | value borrowed here after move | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (U, U); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9 @@ -49,6 +69,11 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ [ref mut b, ref c] = [U, U]; + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 @@ -59,6 +84,11 @@ LL | let a @ ref b = u(); | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ ref b = u(); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9 @@ -70,6 +100,11 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14 @@ -80,6 +115,11 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | value borrowed here after move | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (ref mut b @ ref mut c, d @ ref e) = (u(), u()); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33 @@ -90,6 +130,11 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | value borrowed here after move | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u()); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 @@ -101,6 +146,11 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ [ref mut b, ref c] = [u(), u()]; + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9 @@ -111,6 +161,11 @@ LL | a @ Some(ref b) => {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some(ref b) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9 @@ -122,6 +177,11 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19 @@ -132,6 +192,11 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38 @@ -142,6 +207,11 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9 @@ -153,6 +223,11 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref mut a @ Some([ref b, ref mut c]) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 @@ -163,6 +238,11 @@ LL | a @ Some(ref b) => {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some(ref b) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9 @@ -174,6 +254,11 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19 @@ -184,6 +269,11 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38 @@ -194,6 +284,11 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9 @@ -205,6 +300,11 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref mut a @ Some([ref b, ref mut c]) => {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11 @@ -215,6 +315,11 @@ LL | fn f1(a @ ref b: U) {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | fn f1(ref a @ ref b: U) {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 @@ -226,6 +331,11 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | fn f2(ref mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20 @@ -236,6 +346,11 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | value borrowed here after move | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | fn f2(mut a @ (ref b @ ref c, mut d @ ref e): (U, U)) {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31 @@ -246,6 +361,11 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | value borrowed here after move | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | fn f2(mut a @ (b @ ref c, ref mut d @ ref e): (U, U)) {} + | +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11 @@ -257,6 +377,11 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | fn f3(ref a @ [ref mut b, ref c]: [U; 2]) {} + | +++ error[E0382]: use of partially moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9 @@ -269,8 +394,8 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (U, U); - | +++ +LL | let ref a @ (mut b @ ref mut c, ref d @ ref e) = (U, U); + | +++ +++ error[E0382]: use of partially moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9 @@ -283,8 +408,8 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u()); - | +++ +LL | let ref a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u()); + | +++ +++ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index 384a57b2ee092..ad4ce7952ca74 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -97,6 +97,11 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ (ref mut b, ref mut c) = (U, U); + | +++ error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9 @@ -109,6 +114,11 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ (b, [c, d]) = &mut val; // Same as ^-- + | +++ error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 @@ -119,6 +129,11 @@ LL | let a @ &mut ref mut b = &mut U; | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ &mut ref mut b = &mut U; + | +++ error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9 @@ -130,6 +145,11 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref a @ &mut (ref mut b, ref mut c) = &mut (U, U); + | +++ error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9 diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr index 4ea3dfefb77a3..e0e623fa544f7 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -9,8 +9,8 @@ LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | let a @ NC(b, ref c @ NC(d, e)) = NC(C, NC(C, C)); - | +++ +LL | let ref a @ NC(b, ref c @ NC(d, e)) = NC(C, NC(C, C)); + | +++ +++ error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index 43e4b6990d2a2..638bdd6db7606 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -34,6 +34,11 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | | value borrowed here after move | value moved into `b` here | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | Ok(ref a @ b) | Err(ref b @ ref a) => { + | +++ error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:42:9 diff --git a/src/test/ui/suggestions/ref-pattern-binding.fixed b/src/test/ui/suggestions/ref-pattern-binding.fixed new file mode 100644 index 0000000000000..c36040eeca301 --- /dev/null +++ b/src/test/ui/suggestions/ref-pattern-binding.fixed @@ -0,0 +1,19 @@ +// run-rustfix +#![allow(unused)] + +struct S { + f: String, +} + +fn main() { + let ref _moved @ ref _from = String::from("foo"); //~ ERROR + let ref _moved @ ref _from = String::from("foo"); //~ ERROR + let ref _moved @ ref _from = String::from("foo"); //~ ERROR + //~^ ERROR + let ref _moved @ ref _from = String::from("foo"); // ok + let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR + let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR + //~^ ERROR + let ref _moved @ S { ref f } = S { f: String::from("foo") }; // ok + let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR +} diff --git a/src/test/ui/suggestions/ref-pattern-binding.rs b/src/test/ui/suggestions/ref-pattern-binding.rs new file mode 100644 index 0000000000000..c0d4feb033098 --- /dev/null +++ b/src/test/ui/suggestions/ref-pattern-binding.rs @@ -0,0 +1,19 @@ +// run-rustfix +#![allow(unused)] + +struct S { + f: String, +} + +fn main() { + let _moved @ _from = String::from("foo"); //~ ERROR + let _moved @ ref _from = String::from("foo"); //~ ERROR + let ref _moved @ _from = String::from("foo"); //~ ERROR + //~^ ERROR + let ref _moved @ ref _from = String::from("foo"); // ok + let _moved @ S { f } = S { f: String::from("foo") }; //~ ERROR + let ref _moved @ S { f } = S { f: String::from("foo") }; //~ ERROR + //~^ ERROR + let ref _moved @ S { ref f } = S { f: String::from("foo") }; // ok + let _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR +} diff --git a/src/test/ui/suggestions/ref-pattern-binding.stderr b/src/test/ui/suggestions/ref-pattern-binding.stderr new file mode 100644 index 0000000000000..10447ba7089ca --- /dev/null +++ b/src/test/ui/suggestions/ref-pattern-binding.stderr @@ -0,0 +1,107 @@ +error: borrow of moved value + --> $DIR/ref-pattern-binding.rs:10:9 + | +LL | let _moved @ ref _from = String::from("foo"); + | ------^^^--------- + | | | + | | value borrowed here after move + | value moved into `_moved` here + | move occurs because `_moved` has type `String` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref _moved @ ref _from = String::from("foo"); + | +++ + +error: cannot move out of value because it is borrowed + --> $DIR/ref-pattern-binding.rs:11:9 + | +LL | let ref _moved @ _from = String::from("foo"); + | ----------^^^----- + | | | + | | value moved into `_from` here + | value borrowed, by `_moved`, here + +error: cannot move out of value because it is borrowed + --> $DIR/ref-pattern-binding.rs:15:9 + | +LL | let ref _moved @ S { f } = S { f: String::from("foo") }; + | ----------^^^^^^^-^^ + | | | + | | value moved into `f` here + | value borrowed, by `_moved`, here + +error: borrow of moved value + --> $DIR/ref-pattern-binding.rs:18:9 + | +LL | let _moved @ S { ref f } = S { f: String::from("foo") }; + | ------^^^^^^^-----^^ + | | | + | | value borrowed here after move + | value moved into `_moved` here + | move occurs because `_moved` has type `S` which does not implement the `Copy` trait + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref _moved @ S { ref f } = S { f: String::from("foo") }; + | +++ + +error[E0382]: use of moved value + --> $DIR/ref-pattern-binding.rs:9:9 + | +LL | let _moved @ _from = String::from("foo"); + | ^^^^^^ ----- ------------------- move occurs because value has type `String`, which does not implement the `Copy` trait + | | | + | | value moved here + | value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref _moved @ ref _from = String::from("foo"); + | +++ +++ + +error[E0382]: borrow of moved value + --> $DIR/ref-pattern-binding.rs:11:9 + | +LL | let ref _moved @ _from = String::from("foo"); + | ^^^^^^^^^^ ----- ------------------- move occurs because value has type `String`, which does not implement the `Copy` trait + | | | + | | value moved here + | value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref _moved @ ref _from = String::from("foo"); + | +++ + +error[E0382]: use of partially moved value + --> $DIR/ref-pattern-binding.rs:14:9 + | +LL | let _moved @ S { f } = S { f: String::from("foo") }; + | ^^^^^^ - value partially moved here + | | + | value used here after partial move + | + = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref _moved @ S { ref f } = S { f: String::from("foo") }; + | +++ +++ + +error[E0382]: borrow of partially moved value + --> $DIR/ref-pattern-binding.rs:15:9 + | +LL | let ref _moved @ S { f } = S { f: String::from("foo") }; + | ^^^^^^^^^^ - value partially moved here + | | + | value borrowed here after partial move + | + = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ref _moved @ S { ref f } = S { f: String::from("foo") }; + | +++ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/track-diagnostics/track2.stderr b/src/test/ui/track-diagnostics/track2.stderr index 53f20259a8e5f..fe13e5ef3f546 100644 --- a/src/test/ui/track-diagnostics/track2.stderr +++ b/src/test/ui/track-diagnostics/track2.stderr @@ -10,8 +10,8 @@ LL | let _moved @ _from = String::from("foo"); | help: borrow this binding in the pattern to avoid moving the value | -LL | let _moved @ ref _from = String::from("foo"); - | +++ +LL | let ref _moved @ ref _from = String::from("foo"); + | +++ +++ error: aborting due to previous error From 7cc4fb50e4006649f198d12c1f4ce031ea86b0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar> Date: Tue, 15 Nov 2022 19:43:33 -0800 Subject: [PATCH 33/38] Account for closures --- .../rustc_borrowck/src/diagnostics/conflict_errors.rs | 6 ++++-- compiler/rustc_borrowck/src/diagnostics/mod.rs | 8 +++++--- src/test/ui/closure_context/issue-42065.stderr | 4 ---- src/test/ui/moves/borrow-closures-instead-of-move.stderr | 7 ------- .../unboxed-closures-infer-fnonce-call-twice.stderr | 4 ---- .../unboxed-closures-infer-fnonce-move-call-twice.stderr | 4 ---- 6 files changed, 9 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1f45baef8a805..69948399acf78 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -167,7 +167,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - self.add_moved_or_invoked_closure_note(location, used_place, &mut err); + let closure = self.add_moved_or_invoked_closure_note(location, used_place, &mut err); let mut is_loop_move = false; let mut in_pattern = false; @@ -193,7 +193,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } if !seen_spans.contains(&move_span) { - self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern); + if !closure { + self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern); + } self.explain_captures( &mut err, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 7f26af67c71b2..db85cc7bf31fe 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -70,7 +70,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, place: PlaceRef<'tcx>, diag: &mut Diagnostic, - ) { + ) -> bool { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); let mut target = place.local_or_deref_local(); for stmt in &self.body[location.block].statements[location.statement_index..] { @@ -106,7 +106,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { place.local_or_deref_local().unwrap() } - _ => return, + _ => return false, }; debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); @@ -125,7 +125,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::place_to_string_for_capture(self.infcx.tcx, hir_place) ), ); - return; + return true; } } } @@ -149,9 +149,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::place_to_string_for_capture(self.infcx.tcx, hir_place) ), ); + return true; } } } + false } /// End-user visible description of `place` if one can be found. diff --git a/src/test/ui/closure_context/issue-42065.stderr b/src/test/ui/closure_context/issue-42065.stderr index 4e436ca7c03f5..896bb6dc6bee8 100644 --- a/src/test/ui/closure_context/issue-42065.stderr +++ b/src/test/ui/closure_context/issue-42065.stderr @@ -16,10 +16,6 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | debug_dump_dict(); | ^^^^^^^^^^^^^^^ -help: consider cloning the value if the performance cost is acceptable - | -LL | debug_dump_dict.clone()(); - | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr index fbeeaf646e1ee..9a84ddef7e64e 100644 --- a/src/test/ui/moves/borrow-closures-instead-of-move.stderr +++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr @@ -58,13 +58,6 @@ note: closure cannot be moved more than once as it is not `Copy` due to moving t | LL | x += 1; | ^ -note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary - --> $DIR/borrow-closures-instead-of-move.rs:34:20 - | -LL | fn takes_fnonce(_: impl FnOnce()) {} - | ------------ ^^^^^^^^^^^^^ this parameter takes ownership of the value - | | - | in this function help: consider mutably borrowing `closure` | LL | takes_fnonce(&mut closure); diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr index 3175d2942d5a7..ab6f06518467c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-call-twice.stderr @@ -16,10 +16,6 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | tick(); | ^^^^ -help: consider cloning the value if the performance cost is acceptable - | -LL | tick.clone()(); - | ++++++++ error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr index ffeafb10fda2c..8d70a2b17602b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fnonce-move-call-twice.stderr @@ -16,10 +16,6 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | tick(); | ^^^^ -help: consider cloning the value if the performance cost is acceptable - | -LL | tick.clone()(); - | ++++++++ error: aborting due to previous error From 3099dfdd9fc1a331eb9c53200b310fa1a06e1573 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni <thom@shift.click> Date: Sat, 3 Sep 2022 00:28:03 -0700 Subject: [PATCH 34/38] Forbid inlining `thread_local!`'s `__getit` function on Windows --- library/std/src/thread/local.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 5d267891bb0ed..154b608c0dc5c 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -181,7 +181,8 @@ macro_rules! thread_local { macro_rules! __thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, const $init:expr) => {{ - #[cfg_attr(not(windows), inline)] // see comments below + #[cfg_attr(not(all(windows, target_thread_local)), inline)] // see comments below + #[cfg_attr(all(windows, target_thread_local), inline(never))] #[deny(unsafe_op_in_unsafe_fn)] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, @@ -294,12 +295,17 @@ macro_rules! __thread_local_inner { fn __init() -> $t { $init } // When reading this function you might ask "why is this inlined - // everywhere other than Windows?", and that's a very reasonable - // question to ask. The short story is that it segfaults rustc if - // this function is inlined. The longer story is that Windows looks - // to not support `extern` references to thread locals across DLL - // boundaries. This appears to at least not be supported in the ABI - // that LLVM implements. + // everywhere other than Windows?", and "why must it not be inlined + // on Windows?" and these are very reasonable questions to ask. + // + // The short story is that Windows doesn't support referencing + // `#[thread_local]` across DLL boundaries. The slightly longer + // story is that each module (dll or exe) has its own separate set + // of static thread locals, so if you try and reference a + // `#[thread_local]` that comes from `crate1.dll` from within one of + // `crate2.dll`'s functions, then it might give you a completely + // different thread local than what you asked for (or it might just + // crash). // // Because of this we never inline on Windows, but we do inline on // other platforms (where external references to thread locals @@ -314,8 +320,9 @@ macro_rules! __thread_local_inner { // Cargo question kinda). This means that, unfortunately, Windows // gets the pessimistic path for now where it's never inlined. // - // The issue of "should enable on Windows sometimes" is #84933 - #[cfg_attr(not(windows), inline)] + // The issue of "should improve things on Windows" is #84933 + #[cfg_attr(not(all(windows, target_thread_local)), inline)] + #[cfg_attr(all(windows, target_thread_local), inline(never))] unsafe fn __getit( init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { From 2d5d692053590aa173ffebd3d5fc9707dc39ea9f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume.gomez@huawei.com> Date: Tue, 22 Nov 2022 16:02:37 +0100 Subject: [PATCH 35/38] Add failing test for projections used as const generic --- .../const-generics/projection-as-arg-const.rs | 20 +++++++++++++++++++ .../projection-as-arg-const.stderr | 11 ++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/test/ui/const-generics/projection-as-arg-const.rs create mode 100644 src/test/ui/const-generics/projection-as-arg-const.stderr diff --git a/src/test/ui/const-generics/projection-as-arg-const.rs b/src/test/ui/const-generics/projection-as-arg-const.rs new file mode 100644 index 0000000000000..903548c75db56 --- /dev/null +++ b/src/test/ui/const-generics/projection-as-arg-const.rs @@ -0,0 +1,20 @@ +// This is currently not possible to use projections as const generics. +// More information about this available here: +// https://github.com/rust-lang/rust/pull/104443#discussion_r1029375633 + +pub trait Identity { + type Identity; +} + +impl<T> Identity for T { + type Identity = Self; +} + +pub fn foo<const X: <i32 as Identity>::Identity>() { +//~^ ERROR + assert!(X == 12); +} + +fn main() { + foo::<12>(); +} diff --git a/src/test/ui/const-generics/projection-as-arg-const.stderr b/src/test/ui/const-generics/projection-as-arg-const.stderr new file mode 100644 index 0000000000000..803ed9c959752 --- /dev/null +++ b/src/test/ui/const-generics/projection-as-arg-const.stderr @@ -0,0 +1,11 @@ +error: `<i32 as Identity>::Identity` is forbidden as the type of a const generic parameter + --> $DIR/projection-as-arg-const.rs:13:21 + | +LL | pub fn foo<const X: <i32 as Identity>::Identity>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = help: more complex types are supported with `#![feature(adt_const_params)]` + +error: aborting due to previous error + From 04610ad1297bb092205be59f3faf629a96067ee3 Mon Sep 17 00:00:00 2001 From: Maybe Waffle <waffle.lapkin@gmail.com> Date: Tue, 22 Nov 2022 15:57:06 +0000 Subject: [PATCH 36/38] Fix `ClosureKind::to_def_id` --- compiler/rustc_middle/src/ty/closure.rs | 14 +++++++----- .../mismatched_types/overloaded-calls-bad.rs | 19 +++++++++++----- .../overloaded-calls-bad.stderr | 22 +++++++++++++++---- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 0d6c26a582246..273a61c966c72 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -5,6 +5,7 @@ use crate::{mir, ty}; use std::fmt::Write; +use hir::LangItem; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -130,11 +131,14 @@ impl<'tcx> ClosureKind { } pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId { - match self { - ClosureKind::Fn => tcx.lang_items().fn_once_trait().unwrap(), - ClosureKind::FnMut => tcx.lang_items().fn_mut_trait().unwrap(), - ClosureKind::FnOnce => tcx.lang_items().fn_trait().unwrap(), - } + tcx.require_lang_item( + match self { + ClosureKind::Fn => LangItem::Fn, + ClosureKind::FnMut => LangItem::FnMut, + ClosureKind::FnOnce => LangItem::FnOnce, + }, + None, + ) } } diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.rs b/src/test/ui/mismatched_types/overloaded-calls-bad.rs index 902a6ec81d60b..232cd2ba88cc2 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.rs +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.rs @@ -20,14 +20,23 @@ impl FnOnce<(isize,)> for S { } } +struct F; + +impl FnOnce<(i32,)> for F { + type Output = (); + + extern "rust-call" fn call_once(self, args: (i32,)) -> Self::Output {} +} + fn main() { - let mut s = S { - x: 3, - y: 3, - }; - let ans = s("what"); //~ ERROR mismatched types + let mut s = S { x: 3, y: 3 }; + let ans = s("what"); + //~^ ERROR mismatched types let ans = s(); //~^ ERROR this function takes 1 argument but 0 arguments were supplied let ans = s("burma", "shave"); //~^ ERROR this function takes 1 argument but 2 arguments were supplied + + F(""); + //~^ ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index fb3597aa85300..3a895acbdb5dd 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/overloaded-calls-bad.rs:28:17 + --> $DIR/overloaded-calls-bad.rs:33:17 | LL | let ans = s("what"); | - ^^^^^^ expected `isize`, found `&str` @@ -13,7 +13,7 @@ LL | impl FnMut<(isize,)> for S { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0057]: this function takes 1 argument but 0 arguments were supplied - --> $DIR/overloaded-calls-bad.rs:29:15 + --> $DIR/overloaded-calls-bad.rs:35:15 | LL | let ans = s(); | ^-- an argument of type `isize` is missing @@ -29,7 +29,7 @@ LL | let ans = s(/* isize */); | ~~~~~~~~~~~~~ error[E0057]: this function takes 1 argument but 2 arguments were supplied - --> $DIR/overloaded-calls-bad.rs:31:15 + --> $DIR/overloaded-calls-bad.rs:37:15 | LL | let ans = s("burma", "shave"); | ^ ------- ------- argument of type `&'static str` unexpected @@ -46,7 +46,21 @@ help: remove the extra argument LL | let ans = s(/* isize */); | ~~~~~~~~~~~~~ -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/overloaded-calls-bad.rs:40:7 + | +LL | F(""); + | - ^^ expected `i32`, found `&str` + | | + | arguments to this struct are incorrect + | +note: implementation defined here + --> $DIR/overloaded-calls-bad.rs:25:1 + | +LL | impl FnOnce<(i32,)> for F { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0057, E0308. For more information about an error, try `rustc --explain E0057`. From b80356a5abb127e1b58869978daf1928180f321c Mon Sep 17 00:00:00 2001 From: Maybe Waffle <waffle.lapkin@gmail.com> Date: Tue, 22 Nov 2022 17:19:19 +0000 Subject: [PATCH 37/38] Use `tcx.require_lang_item` instead of unwrapping --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 4 ++-- compiler/rustc_const_eval/src/transform/check_consts/ops.rs | 4 ++-- compiler/rustc_const_eval/src/util/call_kind.rs | 4 ++-- compiler/rustc_hir_analysis/src/coherence/builtin.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 3 ++- compiler/rustc_middle/src/ty/sty.rs | 3 ++- .../src/traits/error_reporting/suggestions.rs | 2 +- 9 files changed, 14 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8f1ae594a9247..5f99d86b4eaff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -7,7 +7,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; -use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; +use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; use rustc_middle::mir::tcx::PlaceTy; @@ -601,7 +601,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { else { return; }; // Try to find predicates on *generic params* that would allow copying `ty` let infcx = tcx.infer_ctxt().build(); - let copy_did = infcx.tcx.lang_items().copy_trait().unwrap(); + let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); let cause = ObligationCause::new( span, self.mir_hir_id(), diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 2d4afd0dc356b..c62c665158779 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -1,7 +1,7 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use hir::def_id::LocalDefId; -use hir::ConstContext; +use hir::{ConstContext, LangItem}; use rustc_errors::{ error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, }; @@ -304,7 +304,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { err.span_note(deref_target, "deref defined here"); } - diag_trait(&mut err, self_ty, tcx.lang_items().deref_trait().unwrap()); + diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => { diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index 5446ccb1a4730..b38a6c551388e 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -3,7 +3,7 @@ //! context. use rustc_hir::def_id::DefId; -use rustc_hir::lang_items; +use rustc_hir::{lang_items, LangItem}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::Ident; @@ -26,7 +26,7 @@ impl CallDesugaringKind { match self { Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), Self::QuestionBranch | Self::TryBlockFromOutput => { - tcx.lang_items().try_trait().unwrap() + tcx.require_lang_item(LangItem::Try, None) } Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b2c9e7389b047..11661215ae1cc 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -114,7 +114,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { traits::ObligationCause::dummy_with_span(field_ty_span), param_env, ty, - tcx.lang_items().copy_trait().unwrap(), + tcx.require_lang_item(LangItem::Copy, Some(span)), ) { let error_predicate = error.obligation.predicate; // Only note if it's not the root obligation, otherwise it's trivial and diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index de30bfe6923a7..5b6fb619217a3 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1118,7 +1118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lhs_deref_ty_is_sized = self .infcx .type_implements_trait( - self.tcx.lang_items().sized_trait().unwrap(), + self.tcx.require_lang_item(LangItem::Sized, None), [lhs_deref_ty], self.param_env, ) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8d6ae14231457..26d30308ed371 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2293,7 +2293,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `ty`, return whether it's an `impl Future<...>`. pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool { let ty::Opaque(def_id, _) = ty.kind() else { return false }; - let future_trait = self.lang_items().future_trait().unwrap(); + let future_trait = self.require_lang_item(LangItem::Future, None); self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| { let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a0c076cbbb245..07012a686f808 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_hir::LangItem; use rustc_session::config::TrimmedDefPaths; use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_session::Limit; @@ -889,7 +890,7 @@ pub trait PrettyPrinter<'tcx>: // Group the return ty with its def id, if we had one. entry .return_ty - .map(|ty| (tcx.lang_items().fn_once_output().unwrap(), ty)), + .map(|ty| (tcx.require_lang_item(LangItem::FnOnce, None), ty)), ); } if let Some(trait_ref) = entry.fn_mut_trait_ref { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index db18558e947a3..e7a751fa0afca 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -17,6 +17,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_index::vec::Idx; use rustc_macros::HashStable; use rustc_span::symbol::{kw, sym, Symbol}; @@ -2108,7 +2109,7 @@ impl<'tcx> Ty<'tcx> { ty::Str | ty::Slice(_) => (tcx.types.usize, false), ty::Dynamic(..) => { - let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap(); + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); (tcx.bound_type_of(dyn_metadata).subst(tcx, &[tail.into()]), false) }, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 8086cac0d551a..186109e7075f1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2625,7 +2625,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }; - let from_generator = tcx.lang_items().from_generator_fn().unwrap(); + let from_generator = tcx.require_lang_item(LangItem::FromGenerator, None); // Don't print the tuple of capture types 'print: { From f2830f2c88124641152243692468b7beca46d399 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Tue, 22 Nov 2022 19:11:12 +0100 Subject: [PATCH 38/38] Speed up mpsc_stress test --- src/test/ui/threads-sendsync/mpsc_stress.rs | 67 ++++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/src/test/ui/threads-sendsync/mpsc_stress.rs b/src/test/ui/threads-sendsync/mpsc_stress.rs index a889542fec0be..c2e1912deb7aa 100644 --- a/src/test/ui/threads-sendsync/mpsc_stress.rs +++ b/src/test/ui/threads-sendsync/mpsc_stress.rs @@ -64,9 +64,11 @@ fn shared_close_sender_does_not_lose_messages_iter() { #[test] fn shared_close_sender_does_not_lose_messages() { - for _ in 0..10000 { - shared_close_sender_does_not_lose_messages_iter(); - } + with_minimum_timer_resolution(|| { + for _ in 0..10000 { + shared_close_sender_does_not_lose_messages_iter(); + } + }); } @@ -96,17 +98,11 @@ fn concurrent_recv_timeout_and_upgrade_iter() { #[test] fn concurrent_recv_timeout_and_upgrade() { - // FIXME: fix and enable - if true { return } - - // at the moment of writing this test fails like this: - // thread '<unnamed>' panicked at 'assertion failed: `(left == right)` - // left: `4561387584`, - // right: `0`', libstd/sync/mpsc/shared.rs:253:13 - - for _ in 0..10000 { - concurrent_recv_timeout_and_upgrade_iter(); - } + with_minimum_timer_resolution(|| { + for _ in 0..10000 { + concurrent_recv_timeout_and_upgrade_iter(); + } + }); } @@ -159,7 +155,46 @@ fn concurrent_writes_iter() { #[test] fn concurrent_writes() { - for _ in 0..100 { - concurrent_writes_iter(); + with_minimum_timer_resolution(|| { + for _ in 0..100 { + concurrent_writes_iter(); + } + }); +} + +#[cfg(windows)] +pub mod timeapi { + #![allow(non_snake_case)] + use std::ffi::c_uint; + + pub const TIMERR_NOERROR: c_uint = 0; + + #[link(name = "winmm")] + extern "system" { + pub fn timeBeginPeriod(uPeriod: c_uint) -> c_uint; + pub fn timeEndPeriod(uPeriod: c_uint) -> c_uint; + } +} + +/// Window's minimum sleep time can be as much as 16ms. +// This function evaluates the closure with this resolution +// set as low as possible. +/// +/// This takes the above test's duration from 10000*16/1000/60=2.67 minutes to ~16 seconds. +fn with_minimum_timer_resolution(f: impl Fn()) { + #[cfg(windows)] + unsafe { + let ret = timeapi::timeBeginPeriod(1); + assert_eq!(ret, timeapi::TIMERR_NOERROR); + + f(); + + let ret = timeapi::timeEndPeriod(1); + assert_eq!(ret, timeapi::TIMERR_NOERROR); + } + + #[cfg(not(windows))] + { + f(); } }