diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index e22a523dbc3..34c539ea16b 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -184,7 +184,7 @@ impl<'a, T> IntoIterator for &'a P<[T]> { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { - self.ptr.into_iter() + self.ptr.iter() } } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index dbb88e42a3e..ebaa9f8d950 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -899,10 +899,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[rustc_main]` attribute is used internally to specify test entry point function", ), rustc_attr!( - rustc_skip_array_during_method_dispatch, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::No, - "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \ - from method dispatch when the receiver is an array, for compatibility in editions < 2021." + rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing, + EncodeCrossCrate::No, + "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \ + from method dispatch when the receiver is of the following type, for compatibility in \ + editions < 2021 (array) or editions < 2024 (boxed_slice)." ), rustc_attr!( rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index aa28b2c8e2c..b760b86a7bf 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1117,8 +1117,24 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let is_marker = tcx.has_attr(def_id, sym::marker); let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive); - let skip_array_during_method_dispatch = - tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch); + + // FIXME: We could probably do way better attribute validation here. + let mut skip_array_during_method_dispatch = false; + let mut skip_boxed_slice_during_method_dispatch = false; + for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) { + if let Some(lst) = attr.meta_item_list() { + for item in lst { + if let Some(ident) = item.ident() { + match ident.as_str() { + "array" => skip_array_during_method_dispatch = true, + "boxed_slice" => skip_boxed_slice_during_method_dispatch = true, + _ => (), + } + } + } + } + } + let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) { ty::trait_def::TraitSpecializationKind::Marker } else if tcx.has_attr(def_id, sym::rustc_specialization_trait) { @@ -1253,6 +1269,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { is_marker, is_coinductive: rustc_coinductive || is_auto, skip_array_during_method_dispatch, + skip_boxed_slice_during_method_dispatch, specialization_kind, must_implement_one_of, implement_via_object, diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index a40fa600c19..4165ccb1b80 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -3,7 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html mod confirm; -mod prelude2021; +mod prelude_edition_lints; pub mod probe; mod suggest; @@ -186,7 +186,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pick = self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; - self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args); + self.lint_edition_dependent_dot_call( + self_ty, segment, span, call_expr, self_expr, &pick, args, + ); for &import_id in &pick.import_ids { debug!("used_trait_import: {:?}", import_id); diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs similarity index 90% rename from compiler/rustc_hir_typeck/src/method/prelude2021.rs rename to compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index eca326892b5..e9eab6969b3 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -1,12 +1,12 @@ -use crate::{ - method::probe::{self, Pick}, - FnCtxt, -}; +use crate::method::probe::{self, Pick}; +use crate::FnCtxt; + use hir::def_id::DefId; use hir::HirId; use hir::ItemKind; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty}; use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS; @@ -17,7 +17,7 @@ use rustc_trait_selection::infer::InferCtxtExt; use std::fmt::Write; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub(super) fn lint_dot_call_from_2018( + pub(super) fn lint_edition_dependent_dot_call( &self, self_ty: Ty<'tcx>, segment: &hir::PathSegment<'_>, @@ -32,22 +32,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment.ident, self_ty, call_expr, self_expr ); - // Rust 2021 and later is already using the new prelude - if span.at_least_rust_2021() { - return; - } - - let prelude_or_array_lint = match segment.ident.name { + let (prelude_or_array_lint, edition) = match segment.ident.name { // `try_into` was added to the prelude in Rust 2021. - sym::try_into => RUST_2021_PRELUDE_COLLISIONS, + sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"), // `into_iter` wasn't added to the prelude, // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter // before Rust 2021, which results in the same problem. // It is only a problem for arrays. - sym::into_iter if let ty::Array(..) = self_ty.kind() => { - // In this case, it wasn't really a prelude addition that was the problem. - // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021. - rustc_lint::ARRAY_INTO_ITER + sym::into_iter => { + if let ty::Array(..) = self_ty.kind() + && !span.at_least_rust_2021() + { + // In this case, it wasn't really a prelude addition that was the problem. + // Instead, the problem is that the array-into_iter hack will no longer + // apply in Rust 2021. + (ARRAY_INTO_ITER, "2021") + } else if self_ty.is_box() + && self_ty.boxed_ty().is_slice() + && !span.at_least_rust_2024() + { + // In this case, it wasn't really a prelude addition that was the problem. + // Instead, the problem is that the boxed-slice-into_iter hack will no + // longer apply in Rust 2024. + (BOXED_SLICE_INTO_ITER, "2024") + } else { + return; + } } _ => return, }; @@ -81,7 +91,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prelude_or_array_lint, self_expr.hir_id, self_expr.span, - format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name), + format!( + "trait method `{}` will become ambiguous in Rust {edition}", + segment.ident.name + ), |lint| { let sp = self_expr.span; @@ -131,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prelude_or_array_lint, call_expr.hir_id, call_expr.span, - format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name), + format!( + "trait method `{}` will become ambiguous in Rust {edition}", + segment.ident.name + ), |lint| { let sp = call_expr.span; let trait_name = self.trait_path_or_bare_name( diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 60a63d72d40..e0a60337c3b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1444,6 +1444,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return ProbeResult::NoMatch; } } + + // Some trait methods are excluded for boxed slices before 2024. + // (`boxed_slice.into_iter()` wants a slice iterator for compatibility.) + if self_ty.is_box() + && self_ty.boxed_ty().is_slice() + && !method_name.span.at_least_rust_2024() + { + let trait_def = self.tcx.trait_def(poly_trait_ref.def_id()); + if trait_def.skip_boxed_slice_during_method_dispatch { + return ProbeResult::NoMatch; + } + } } let trait_ref = self.instantiate_binder_with_fresh_vars( diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 5180fce2eb3..cf9d089ff62 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -2,13 +2,6 @@ lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses -lint_array_into_iter = - this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021 - .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity - .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value - .use_explicit_into_iter_suggestion = - or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` .suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change @@ -565,6 +558,13 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}` lint_requested_level = requested on the command line with `{$level} {$lint_name}` +lint_shadowed_into_iter = + this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition} + .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity + .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value + .use_explicit_into_iter_suggestion = + or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs deleted file mode 100644 index 8f4bae33957..00000000000 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::{ - lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub}, - LateContext, LateLintPass, LintContext, -}; -use rustc_hir as hir; -use rustc_middle::bug; -use rustc_middle::ty; -use rustc_middle::ty::adjustment::{Adjust, Adjustment}; -use rustc_session::lint::FutureIncompatibilityReason; -use rustc_session::{declare_lint, impl_lint_pass}; -use rustc_span::edition::Edition; -use rustc_span::symbol::sym; -use rustc_span::Span; - -declare_lint! { - /// The `array_into_iter` lint detects calling `into_iter` on arrays. - /// - /// ### Example - /// - /// ```rust,edition2018 - /// # #![allow(unused)] - /// [1, 2, 3].into_iter().for_each(|n| { *n; }); - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid - /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still - /// behave as `(&array).into_iter()`, returning an iterator over - /// references, just like in Rust 1.52 and earlier. - /// This only applies to the method call syntax `array.into_iter()`, not to - /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`. - pub ARRAY_INTO_ITER, - Warn, - "detects calling `into_iter` on arrays in Rust 2015 and 2018", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021), - reference: "", - }; -} - -#[derive(Copy, Clone, Default)] -pub struct ArrayIntoIter { - for_expr_span: Span, -} - -impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]); - -impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - // Save the span of expressions in `for _ in expr` syntax, - // so we can give a better suggestion for those later. - if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind { - if let hir::ExprKind::Call(path, [arg]) = &arg.kind { - if let hir::ExprKind::Path(hir::QPath::LangItem( - hir::LangItem::IntoIterIntoIter, - .., - )) = &path.kind - { - self.for_expr_span = arg.span; - } - } - } - - // We only care about method call expressions. - if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind { - if call.ident.name != sym::into_iter { - return; - } - - // Check if the method call actually calls the libcore - // `IntoIterator::into_iter`. - let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - match cx.tcx.trait_of_item(def_id) { - Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {} - _ => return, - }; - - // As this is a method call expression, we have at least one argument. - let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); - let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); - - let Some(Adjustment { kind: Adjust::Borrow(_), target }) = adjustments.last() else { - return; - }; - - let types = - std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target)); - - let mut found_array = false; - - for ty in types { - match ty.kind() { - // If we run into a &[T; N] or &[T] first, there's nothing to warn about. - // It'll resolve to the reference version. - ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return, - ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return, - // Found an actual array type without matching a &[T; N] first. - // This is the problematic case. - ty::Array(..) => { - found_array = true; - break; - } - _ => {} - } - } - - if !found_array { - return; - } - - // Emit lint diagnostic. - let target = match *target.kind() { - ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]", - ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]", - // We know the original first argument type is an array type, - // we know that the first adjustment was an autoref coercion - // and we know that `IntoIterator` is the trait involved. The - // array cannot be coerced to something other than a reference - // to an array or to a slice. - _ => bug!("array type coerced to something other than array or slice"), - }; - let sub = if self.for_expr_span == expr.span { - Some(ArrayIntoIterDiagSub::RemoveIntoIter { - span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), - }) - } else if receiver_ty.is_array() { - Some(ArrayIntoIterDiagSub::UseExplicitIntoIter { - start_span: expr.span.shrink_to_lo(), - end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), - }) - } else { - None - }; - cx.emit_span_lint( - ARRAY_INTO_ITER, - call.ident.span, - ArrayIntoIterDiag { target, suggestion: call.ident.span, sub }, - ); - } - } -} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d93edadcfbc..64fcc7e46e0 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -42,7 +42,6 @@ #[macro_use] extern crate tracing; -mod array_into_iter; mod async_fn_in_trait; pub mod builtin; mod context; @@ -76,18 +75,18 @@ mod passes; mod ptr_nulls; mod redundant_semicolon; mod reference_casting; +mod shadowed_into_iter; mod traits; mod types; mod unit_bindings; mod unused; -pub use array_into_iter::ARRAY_INTO_ITER; +pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_hir::def_id::LocalModDefId; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use array_into_iter::ArrayIntoIter; use async_fn_in_trait::AsyncFnInTrait; use builtin::*; use deref_into_dyn_supertrait::*; @@ -112,6 +111,7 @@ use pass_by_value::*; use ptr_nulls::*; use redundant_semicolon::*; use reference_casting::*; +use shadowed_into_iter::ShadowedIntoIter; use traits::*; use types::*; use unit_bindings::*; @@ -215,7 +215,7 @@ late_lint_methods!( DerefNullPtr: DerefNullPtr, UnstableFeatures: UnstableFeatures, UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller, - ArrayIntoIter: ArrayIntoIter::default(), + ShadowedIntoIter: ShadowedIntoIter, DropTraitConstraints: DropTraitConstraints, TemporaryCStringAsPtr: TemporaryCStringAsPtr, NonPanicFmt: NonPanicFmt, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 7efa5245baa..bc0c8cf85d8 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -22,17 +22,18 @@ use crate::{ // array_into_iter.rs #[derive(LintDiagnostic)] -#[diag(lint_array_into_iter)] -pub struct ArrayIntoIterDiag<'a> { - pub target: &'a str, +#[diag(lint_shadowed_into_iter)] +pub struct ShadowedIntoIterDiag { + pub target: &'static str, + pub edition: &'static str, #[suggestion(lint_use_iter_suggestion, code = "iter", applicability = "machine-applicable")] pub suggestion: Span, #[subdiagnostic] - pub sub: Option, + pub sub: Option, } #[derive(Subdiagnostic)] -pub enum ArrayIntoIterDiagSub { +pub enum ShadowedIntoIterDiagSub { #[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")] RemoveIntoIter { #[primary_span] diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs new file mode 100644 index 00000000000..41ec84faa78 --- /dev/null +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -0,0 +1,157 @@ +use crate::lints::{ShadowedIntoIterDiag, ShadowedIntoIterDiagSub}; +use crate::{LateContext, LateLintPass, LintContext}; +use rustc_hir as hir; +use rustc_middle::ty::{self, Ty}; +use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::{declare_lint, impl_lint_pass}; +use rustc_span::edition::Edition; + +declare_lint! { + /// The `array_into_iter` lint detects calling `into_iter` on arrays. + /// + /// ### Example + /// + /// ```rust,edition2018 + /// # #![allow(unused)] + /// [1, 2, 3].into_iter().for_each(|n| { *n; }); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid + /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still + /// behave as `(&array).into_iter()`, returning an iterator over + /// references, just like in Rust 1.52 and earlier. + /// This only applies to the method call syntax `array.into_iter()`, not to + /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`. + pub ARRAY_INTO_ITER, + Warn, + "detects calling `into_iter` on arrays in Rust 2015 and 2018", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021), + reference: "", + }; +} + +declare_lint! { + /// The `boxed_slice_into_iter` lint detects calling `into_iter` on boxed slices. + /// + /// ### Example + /// + /// ```rust,edition2021 + /// # #![allow(unused)] + /// vec![1, 2, 3].into_boxed_slice().into_iter().for_each(|n| { *n; }); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Since Rust CURRENT_RUSTC_VERSION, boxed slices implement `IntoIterator`. However, to avoid + /// breakage, `boxed_slice.into_iter()` in Rust 2015, 2018, and 2021 code will still + /// behave as `(&boxed_slice).into_iter()`, returning an iterator over + /// references, just like in Rust CURRENT_RUSTC_VERSION and earlier. + /// This only applies to the method call syntax `boxed_slice.into_iter()`, not to + /// any other syntax such as `for _ in boxed_slice` or `IntoIterator::into_iter(boxed_slice)`. + pub BOXED_SLICE_INTO_ITER, + Warn, + "detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + }; +} + +#[derive(Copy, Clone)] +pub struct ShadowedIntoIter; + +impl_lint_pass!(ShadowedIntoIter => [ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER]); + +impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind else { + return; + }; + + // Check if the method call actually calls the libcore + // `IntoIterator::into_iter`. + let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else { + return; + }; + if Some(method_def_id) != cx.tcx.lang_items().into_iter_fn() { + return; + } + + // As this is a method call expression, we have at least one argument. + let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); + let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); + + let adjusted_receiver_tys: Vec<_> = + [receiver_ty].into_iter().chain(adjustments.iter().map(|adj| adj.target)).collect(); + + fn is_ref_to_array(ty: Ty<'_>) -> bool { + if let ty::Ref(_, pointee_ty, _) = *ty.kind() { pointee_ty.is_array() } else { false } + } + fn is_boxed_slice(ty: Ty<'_>) -> bool { + ty.is_box() && ty.boxed_ty().is_slice() + } + fn is_ref_to_boxed_slice(ty: Ty<'_>) -> bool { + if let ty::Ref(_, pointee_ty, _) = *ty.kind() { + is_boxed_slice(pointee_ty) + } else { + false + } + } + + let (lint, target, edition, can_suggest_ufcs) = + if is_ref_to_array(*adjusted_receiver_tys.last().unwrap()) + && let Some(idx) = adjusted_receiver_tys + .iter() + .copied() + .take_while(|ty| !is_ref_to_array(*ty)) + .position(|ty| ty.is_array()) + { + (ARRAY_INTO_ITER, "[T; N]", "2021", idx == 0) + } else if is_ref_to_boxed_slice(*adjusted_receiver_tys.last().unwrap()) + && let Some(idx) = adjusted_receiver_tys + .iter() + .copied() + .take_while(|ty| !is_ref_to_boxed_slice(*ty)) + .position(|ty| is_boxed_slice(ty)) + { + (BOXED_SLICE_INTO_ITER, "Box<[T]>", "2024", idx == 0) + } else { + return; + }; + + // If this expression comes from the `IntoIter::into_iter` inside of a for loop, + // we should just suggest removing the `.into_iter()` or changing it to `.iter()` + // to disambiguate if we want to iterate by-value or by-ref. + let sub = if let Some((_, hir::Node::Expr(parent_expr))) = + cx.tcx.hir().parent_iter(expr.hir_id).nth(1) + && let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = + &parent_expr.kind + && let hir::ExprKind::Call(path, [_]) = &arg.kind + && let hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoIterIntoIter, ..)) = + &path.kind + { + Some(ShadowedIntoIterDiagSub::RemoveIntoIter { + span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + }) + } else if can_suggest_ufcs { + Some(ShadowedIntoIterDiagSub::UseExplicitIntoIter { + start_span: expr.span.shrink_to_lo(), + end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + }) + } else { + None + }; + + cx.emit_span_lint( + lint, + call.ident.span, + ShadowedIntoIterDiag { target, edition, suggestion: call.ident.span, sub }, + ); + } +} diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index c5b3de17bcb..cf1cbb93410 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -39,11 +39,16 @@ pub struct TraitDef { /// also have already switched to the new trait solver. pub is_coinductive: bool, - /// If `true`, then this trait has the `#[rustc_skip_array_during_method_dispatch]` + /// If `true`, then this trait has the `#[rustc_skip_during_method_dispatch(array)]` /// attribute, indicating that editions before 2021 should not consider this trait /// during method dispatch if the receiver is an array. pub skip_array_during_method_dispatch: bool, + /// If `true`, then this trait has the `#[rustc_skip_during_method_dispatch(boxed_slice)]` + /// attribute, indicating that editions before 2024 should not consider this trait + /// during method dispatch if the receiver is a boxed slice. + pub skip_boxed_slice_during_method_dispatch: bool, + /// Used to determine whether the standard library is allowed to specialize /// on this trait. pub specialization_kind: TraitSpecializationKind, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index d59318be720..15447983abb 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -505,6 +505,7 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef { is_marker: self.is_marker, is_coinductive: self.is_coinductive, skip_array_during_method_dispatch: self.skip_array_during_method_dispatch, + skip_boxed_slice_during_method_dispatch: self.skip_boxed_slice_during_method_dispatch, specialization_kind: self.specialization_kind.stable(tables), must_implement_one_of: self .must_implement_one_of diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e453c03e7ce..1869daf7e12 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1633,7 +1633,7 @@ symbols! { rustc_reservation_impl, rustc_safe_intrinsic, rustc_serialize, - rustc_skip_array_during_method_dispatch, + rustc_skip_during_method_dispatch, rustc_specialization_trait, rustc_std_internal_symbol, rustc_strict_coherence, diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 759e3f166bd..321c56b623a 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1205,6 +1205,7 @@ pub struct TraitDecl { pub is_marker: bool, pub is_coinductive: bool, pub skip_array_during_method_dispatch: bool, + pub skip_boxed_slice_during_method_dispatch: bool, pub specialization_kind: TraitSpecializationKind, pub must_implement_one_of: Option>, pub implement_via_object: bool, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index f1a6df94e11..21d00503001 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -135,6 +135,45 @@ //! is not allowed. For more guidance on working with box from unsafe code, see //! [rust-lang/unsafe-code-guidelines#326][ucg#326]. //! +//! # Editions +//! +//! A special case exists for the implementation of `IntoIterator` for arrays on the Rust 2021 +//! edition, as documented [here][array]. Unfortunately, it was later found that a similar +//! workaround should be added for boxed slices, and this was applied in the 2024 edition. +//! +//! Specifically, `IntoIterator` is implemented for `Box<[T]>` on all editions, but specific calls +//! to `into_iter()` for boxed slices will defer to the slice implementation on editions before +//! 2024: +//! +#![cfg_attr(bootstrap, doc = "```rust,edition2021,ignore")] +#![cfg_attr(not(bootstrap), doc = "```rust,edition2021")] +//! // Rust 2015, 2018, and 2021: +//! +//! # #![allow(boxed_slice_into_iter)] // override our `deny(warnings)` +//! let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice(); +//! +//! // This creates a slice iterator, producing references to each value. +//! for item in boxed_slice.into_iter().enumerate() { +//! let (i, x): (usize, &i32) = item; +//! println!("boxed_slice[{i}] = {x}"); +//! } +//! +//! // The `boxed_slice_into_iter` lint suggests this change for future compatibility: +//! for item in boxed_slice.iter().enumerate() { +//! let (i, x): (usize, &i32) = item; +//! println!("boxed_slice[{i}] = {x}"); +//! } +//! +//! // You can explicitly iterate a boxed slice by value using `IntoIterator::into_iter` +//! for item in IntoIterator::into_iter(boxed_slice).enumerate() { +//! let (i, x): (usize, i32) = item; +//! println!("boxed_slice[{i}] = {x}"); +//! } +//! ``` +//! +//! Similar to the array implementation, this may be modified in the future to remove this override, +//! and it's best to avoid relying on this edition-dependent behavior if you wish to preserve +//! compatibility with future versions of the compiler. //! //! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198 //! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326 @@ -165,6 +204,7 @@ use core::ops::{ }; use core::pin::Pin; use core::ptr::{self, addr_of_mut, NonNull, Unique}; +use core::slice; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] @@ -177,6 +217,7 @@ use crate::raw_vec::RawVec; use crate::str::from_boxed_utf8_unchecked; #[cfg(not(no_global_oom_handling))] use crate::string::String; +use crate::vec; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; @@ -2080,6 +2121,51 @@ impl FromIterator for Box<[I]> { } } +/// This implementation is required to make sure that the `Box<[I]>: IntoIterator` +/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl !Iterator for Box<[I], A> {} + +/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator` +/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {} + +/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator` +/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket. +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {} + +// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator` +// hides this implementation from explicit `.into_iter()` calls on editions < 2024, +// so those calls will still resolve to the slice implementation, by reference. +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl IntoIterator for Box<[I], A> { + type IntoIter = vec::IntoIter; + type Item = I; + fn into_iter(self) -> vec::IntoIter { + self.into_vec().into_iter() + } +} + +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> { + type IntoIter = slice::Iter<'a, I>; + type Item = &'a I; + fn into_iter(self) -> slice::Iter<'a, I> { + self.iter() + } +} + +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> { + type IntoIter = slice::IterMut<'a, I>; + type Item = &'a mut I; + fn into_iter(self) -> slice::IterMut<'a, I> { + self.iter_mut() + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")] impl FromIterator for Box { diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index e3d2cd2a31f..b314d0536a3 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -38,7 +38,7 @@ pub struct IntoIter { alive: IndexRange, } -// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator` +// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator` // hides this implementation from explicit `.into_iter()` calls on editions < 2021, // so those calls will still resolve to the slice implementation, by reference. #[stable(feature = "array_into_iter_impl", since = "1.53.0")] diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 563781230c0..d9d860c7b6c 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -268,7 +268,6 @@ where /// } /// ``` #[rustc_diagnostic_item = "IntoIterator"] -#[rustc_skip_array_during_method_dispatch] #[rustc_on_unimplemented( on( _Self = "core::ops::range::RangeTo", @@ -312,6 +311,8 @@ where label = "`{Self}` is not an iterator", message = "`{Self}` is not an iterator" )] +#[cfg_attr(bootstrap, rustc_skip_array_during_method_dispatch)] +#[cfg_attr(not(bootstrap), rustc_skip_during_method_dispatch(array, boxed_slice))] #[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { /// The type of the elements being iterated over. diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index d7d4f90c1a5..96fc87ab2e9 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -16,6 +16,9 @@ use crate::ptr::{self, without_provenance, without_provenance_mut, NonNull}; use super::{from_raw_parts, from_raw_parts_mut}; +#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")] +impl !Iterator for [T] {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> IntoIterator for &'a [T] { type Item = &'a T; diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed index c03d91c797c..72b39c982bf 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed @@ -11,7 +11,6 @@ fn main() { let _ = vec![1, 2, 3].into_iter(); let _ = (&vec![1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter() - let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ ERROR: equivalent to `.iter() let _ = std::rc::Rc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter() let _ = std::sync::Arc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter() diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs index 93c732fd6cc..5ba224720d3 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs @@ -11,7 +11,6 @@ fn main() { let _ = vec![1, 2, 3].into_iter(); let _ = (&vec![1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ ERROR: equivalent to `.iter() let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter() let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter() diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr index 0e9d485f1a9..64d814074da 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr @@ -8,160 +8,154 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); = help: to override `-D warnings` add `#[allow(clippy::into_iter_on_ref)]` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` - --> tests/ui/into_iter_on_ref.rs:14:46 - | -LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); - | ^^^^^^^^^ help: call directly: `iter` - -error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` - --> tests/ui/into_iter_on_ref.rs:15:41 + --> tests/ui/into_iter_on_ref.rs:14:41 | LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` - --> tests/ui/into_iter_on_ref.rs:16:44 + --> tests/ui/into_iter_on_ref.rs:15:44 | LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:18:32 + --> tests/ui/into_iter_on_ref.rs:17:32 | LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:19:36 + --> tests/ui/into_iter_on_ref.rs:18:36 | LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:20:40 + --> tests/ui/into_iter_on_ref.rs:19:40 | LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option` - --> tests/ui/into_iter_on_ref.rs:22:24 + --> tests/ui/into_iter_on_ref.rs:21:24 | LL | let _ = (&Some(4)).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option` - --> tests/ui/into_iter_on_ref.rs:23:28 + --> tests/ui/into_iter_on_ref.rs:22:28 | LL | let _ = (&mut Some(5)).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result` - --> tests/ui/into_iter_on_ref.rs:24:32 + --> tests/ui/into_iter_on_ref.rs:23:32 | LL | let _ = (&Ok::<_, i32>(6)).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result` - --> tests/ui/into_iter_on_ref.rs:25:37 + --> tests/ui/into_iter_on_ref.rs:24:37 | LL | let _ = (&mut Err::(7)).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` - --> tests/ui/into_iter_on_ref.rs:26:34 + --> tests/ui/into_iter_on_ref.rs:25:34 | LL | let _ = (&Vec::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec` - --> tests/ui/into_iter_on_ref.rs:27:38 + --> tests/ui/into_iter_on_ref.rs:26:38 | LL | let _ = (&mut Vec::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap` - --> tests/ui/into_iter_on_ref.rs:28:44 + --> tests/ui/into_iter_on_ref.rs:27:44 | LL | let _ = (&BTreeMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap` - --> tests/ui/into_iter_on_ref.rs:29:48 + --> tests/ui/into_iter_on_ref.rs:28:48 | LL | let _ = (&mut BTreeMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque` - --> tests/ui/into_iter_on_ref.rs:30:39 + --> tests/ui/into_iter_on_ref.rs:29:39 | LL | let _ = (&VecDeque::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque` - --> tests/ui/into_iter_on_ref.rs:31:43 + --> tests/ui/into_iter_on_ref.rs:30:43 | LL | let _ = (&mut VecDeque::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList` - --> tests/ui/into_iter_on_ref.rs:32:41 + --> tests/ui/into_iter_on_ref.rs:31:41 | LL | let _ = (&LinkedList::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList` - --> tests/ui/into_iter_on_ref.rs:33:45 + --> tests/ui/into_iter_on_ref.rs:32:45 | LL | let _ = (&mut LinkedList::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap` - --> tests/ui/into_iter_on_ref.rs:34:43 + --> tests/ui/into_iter_on_ref.rs:33:43 | LL | let _ = (&HashMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap` - --> tests/ui/into_iter_on_ref.rs:35:47 + --> tests/ui/into_iter_on_ref.rs:34:47 | LL | let _ = (&mut HashMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet` - --> tests/ui/into_iter_on_ref.rs:37:39 + --> tests/ui/into_iter_on_ref.rs:36:39 | LL | let _ = (&BTreeSet::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap` - --> tests/ui/into_iter_on_ref.rs:38:41 + --> tests/ui/into_iter_on_ref.rs:37:41 | LL | let _ = (&BinaryHeap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet` - --> tests/ui/into_iter_on_ref.rs:39:38 + --> tests/ui/into_iter_on_ref.rs:38:38 | LL | let _ = (&HashSet::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path` - --> tests/ui/into_iter_on_ref.rs:40:43 + --> tests/ui/into_iter_on_ref.rs:39:43 | LL | let _ = std::path::Path::new("12/34").into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf` - --> tests/ui/into_iter_on_ref.rs:41:47 + --> tests/ui/into_iter_on_ref.rs:40:47 | LL | let _ = std::path::PathBuf::from("12/34").into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:43:26 + --> tests/ui/into_iter_on_ref.rs:42:26 | LL | let _ = (&[1, 2, 3]).into_iter().next(); | ^^^^^^^^^ help: call directly: `iter` -error: aborting due to 27 previous errors +error: aborting due to 26 previous errors diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs index 97a70103e64..a20539ee7c7 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs @@ -5,7 +5,7 @@ extern "Rust" { fn main() { let frames = unsafe { miri_get_backtrace(0) }; - for frame in frames.into_iter() { + for frame in frames.iter() { unsafe { miri_resolve_frame(*frame, 0); //~ ERROR: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields } diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs index 8d3173da400..3fff7921aff 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs @@ -27,7 +27,7 @@ fn func_d() -> Box<[*mut ()]> { fn main() { let mut seen_main = false; let frames = func_a(); - for frame in frames.into_iter() { + for frame in frames.iter() { let miri_frame = unsafe { miri_resolve_frame(*frame, 0) }; let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs index ad05271ca51..a3060abc394 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs @@ -32,7 +32,7 @@ fn func_d() -> Box<[*mut ()]> { fn main() { let mut seen_main = false; let frames = func_a(); - for frame in frames.into_iter() { + for frame in frames.iter() { let miri_frame = unsafe { miri_resolve_frame(*frame, 1) }; let mut name = vec![0; miri_frame.name_len]; diff --git a/tests/ui/iterators/into-iter-on-arrays-2018.stderr b/tests/ui/iterators/into-iter-on-arrays-2018.stderr index 2378476e5d0..9d6bbf06c36 100644 --- a/tests/ui/iterators/into-iter-on-arrays-2018.stderr +++ b/tests/ui/iterators/into-iter-on-arrays-2018.stderr @@ -1,4 +1,4 @@ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:14:34 | LL | let _: Iter<'_, i32> = array.into_iter(); @@ -16,7 +16,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | let _: Iter<'_, i32> = IntoIterator::into_iter(array); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:18:44 | LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); @@ -25,7 +25,7 @@ LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:22:43 | LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); @@ -34,7 +34,7 @@ LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:25:41 | LL | let _: Iter<'_, i32> = Array(array).into_iter(); @@ -43,7 +43,7 @@ LL | let _: Iter<'_, i32> = Array(array).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:32:24 | LL | for _ in [1, 2, 3].into_iter() {} diff --git a/tests/ui/iterators/into-iter-on-arrays-lint.stderr b/tests/ui/iterators/into-iter-on-arrays-lint.stderr index 2fde276faa3..da388d6b848 100644 --- a/tests/ui/iterators/into-iter-on-arrays-lint.stderr +++ b/tests/ui/iterators/into-iter-on-arrays-lint.stderr @@ -1,4 +1,4 @@ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:11:11 | LL | small.into_iter(); @@ -16,7 +16,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter(small); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:14:12 | LL | [1, 2].into_iter(); @@ -33,7 +33,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter([1, 2]); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:17:9 | LL | big.into_iter(); @@ -50,7 +50,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter(big); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:20:15 | LL | [0u8; 33].into_iter(); @@ -67,7 +67,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter([0u8; 33]); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:24:21 | LL | Box::new(small).into_iter(); @@ -76,7 +76,7 @@ LL | Box::new(small).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:27:22 | LL | Box::new([1, 2]).into_iter(); @@ -85,7 +85,7 @@ LL | Box::new([1, 2]).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:30:19 | LL | Box::new(big).into_iter(); @@ -94,7 +94,7 @@ LL | Box::new(big).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:33:25 | LL | Box::new([0u8; 33]).into_iter(); @@ -103,7 +103,7 @@ LL | Box::new([0u8; 33]).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:37:31 | LL | Box::new(Box::new(small)).into_iter(); @@ -112,7 +112,7 @@ LL | Box::new(Box::new(small)).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:40:32 | LL | Box::new(Box::new([1, 2])).into_iter(); @@ -121,7 +121,7 @@ LL | Box::new(Box::new([1, 2])).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:43:29 | LL | Box::new(Box::new(big)).into_iter(); @@ -130,7 +130,7 @@ LL | Box::new(Box::new(big)).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:46:35 | LL | Box::new(Box::new([0u8; 33])).into_iter(); diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs b/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs new file mode 100644 index 00000000000..3d9d131e59c --- /dev/null +++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs @@ -0,0 +1,46 @@ +//@ check-pass +//@ edition:2018 + +use std::ops::Deref; +use std::rc::Rc; +use std::slice::Iter; +use std::vec::IntoIter; + +fn main() { + let boxed_slice = vec![0; 10].into_boxed_slice(); + + // Before 2024, the method dispatched to `IntoIterator for Box<[T]>`, + // which we continue to support for compatibility. + let _: Iter<'_, i32> = boxed_slice.into_iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + + let _: Iter<'_, i32> = Box::new(boxed_slice.clone()).into_iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + + let _: Iter<'_, i32> = Rc::new(boxed_slice.clone()).into_iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + let _: Iter<'_, i32> = Array(boxed_slice.clone()).into_iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + + // But you can always use the trait method explicitly as an boxed_slice. + let _: IntoIter = IntoIterator::into_iter(boxed_slice); + + for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {} + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning +} + +/// User type that dereferences to a boxed slice. +struct Array(Box<[i32]>); + +impl Deref for Array { + type Target = Box<[i32]>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr new file mode 100644 index 00000000000..d7f38a23725 --- /dev/null +++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr @@ -0,0 +1,60 @@ +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-2021.rs:14:40 + | +LL | let _: Iter<'_, i32> = boxed_slice.into_iter(); + | ^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: `#[warn(boxed_slice_into_iter)]` on by default +help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + | +LL | let _: Iter<'_, i32> = boxed_slice.iter(); + | ~~~~ +help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + | +LL | let _: Iter<'_, i32> = IntoIterator::into_iter(boxed_slice); + | ++++++++++++++++++++++++ ~ + +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-2021.rs:18:58 + | +LL | let _: Iter<'_, i32> = Box::new(boxed_slice.clone()).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2024 + +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-2021.rs:22:57 + | +LL | let _: Iter<'_, i32> = Rc::new(boxed_slice.clone()).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2024 + +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-2021.rs:25:55 + | +LL | let _: Iter<'_, i32> = Array(boxed_slice.clone()).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2024 + +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-2021.rs:32:48 + | +LL | for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {} + | ^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 +help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + | +LL | for _ in (Box::new([1, 2, 3]) as Box<[_]>).iter() {} + | ~~~~ +help: or remove `.into_iter()` to iterate by value + | +LL - for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {} +LL + for _ in (Box::new([1, 2, 3]) as Box<[_]>) {} + | + +warning: 5 warnings emitted + diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs new file mode 100644 index 00000000000..ffd6f022bc6 --- /dev/null +++ b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs @@ -0,0 +1,20 @@ +//@ check-pass +//@ edition:2024 +//@ compile-flags: -Zunstable-options + +use std::ops::Deref; +use std::rc::Rc; +use std::vec::IntoIter; + +fn main() { + let boxed_slice = vec![0; 10].into_boxed_slice(); + + // In 2021, the method dispatches to `IntoIterator for [T; N]`. + let _: IntoIter = boxed_slice.clone().into_iter(); + + // And through other boxes. + let _: IntoIter = Box::new(boxed_slice.clone()).into_iter(); + + // You can always use the trait method explicitly as a boxed_slice. + let _: IntoIter = IntoIterator::into_iter(boxed_slice.clone()); +} diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed b/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed new file mode 100644 index 00000000000..265a6c764d2 --- /dev/null +++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed @@ -0,0 +1,30 @@ +//@ run-pass +//@ run-rustfix +//@ rustfix-only-machine-applicable + +#[allow(unused_must_use, unused_allocation)] +fn main() { + let boxed = vec![1, 2].into_boxed_slice(); + + // Expressions that should trigger the lint + boxed.iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + Box::new(boxed.clone()).iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + Box::new(Box::new(boxed.clone())).iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + + // Expressions that should not + (&boxed).into_iter(); + + for _ in &boxed {} + (&boxed as &[_]).into_iter(); + boxed[..].into_iter(); + std::iter::IntoIterator::into_iter(&boxed); + + #[allow(boxed_slice_into_iter)] + boxed.into_iter(); +} diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs b/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs new file mode 100644 index 00000000000..dd78e481e0e --- /dev/null +++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs @@ -0,0 +1,30 @@ +//@ run-pass +//@ run-rustfix +//@ rustfix-only-machine-applicable + +#[allow(unused_must_use, unused_allocation)] +fn main() { + let boxed = vec![1, 2].into_boxed_slice(); + + // Expressions that should trigger the lint + boxed.into_iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + Box::new(boxed.clone()).into_iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + Box::new(Box::new(boxed.clone())).into_iter(); + //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` + //~| WARNING this changes meaning + + // Expressions that should not + (&boxed).into_iter(); + + for _ in &boxed {} + (&boxed as &[_]).into_iter(); + boxed[..].into_iter(); + std::iter::IntoIterator::into_iter(&boxed); + + #[allow(boxed_slice_into_iter)] + boxed.into_iter(); +} diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr new file mode 100644 index 00000000000..b73faf0dbd3 --- /dev/null +++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr @@ -0,0 +1,35 @@ +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-lint.rs:10:11 + | +LL | boxed.into_iter(); + | ^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: `#[warn(boxed_slice_into_iter)]` on by default +help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + | +LL | boxed.iter(); + | ~~~~ +help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + | +LL | IntoIterator::into_iter(boxed); + | ++++++++++++++++++++++++ ~ + +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-lint.rs:13:29 + | +LL | Box::new(boxed.clone()).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2024 + +warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to ` as IntoIterator>::into_iter` in Rust 2024 + --> $DIR/into-iter-on-boxed-slices-lint.rs:16:39 + | +LL | Box::new(Box::new(boxed.clone())).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2024 + +warning: 3 warnings emitted + diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed new file mode 100644 index 00000000000..d49fee55a05 --- /dev/null +++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed @@ -0,0 +1,27 @@ +// See https://github.com/rust-lang/rust/issues/88475 +//@ run-rustfix +//@ edition:2021 +//@ check-pass +#![warn(boxed_slice_into_iter)] +#![allow(unused)] + +struct FooIter; + +trait MyIntoIter { + fn into_iter(self) -> FooIter; +} + +impl MyIntoIter for Box<[T]> { + fn into_iter(self) -> FooIter { + FooIter + } +} + +struct Point; + +pub fn main() { + let points: Box<[_]> = vec![Point].into_boxed_slice(); + let y = MyIntoIter::into_iter(points); + //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2024 + //~| WARNING this changes meaning in Rust 2024 +} diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs new file mode 100644 index 00000000000..e78f550d226 --- /dev/null +++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs @@ -0,0 +1,27 @@ +// See https://github.com/rust-lang/rust/issues/88475 +//@ run-rustfix +//@ edition:2021 +//@ check-pass +#![warn(boxed_slice_into_iter)] +#![allow(unused)] + +struct FooIter; + +trait MyIntoIter { + fn into_iter(self) -> FooIter; +} + +impl MyIntoIter for Box<[T]> { + fn into_iter(self) -> FooIter { + FooIter + } +} + +struct Point; + +pub fn main() { + let points: Box<[_]> = vec![Point].into_boxed_slice(); + let y = points.into_iter(); + //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2024 + //~| WARNING this changes meaning in Rust 2024 +} diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr new file mode 100644 index 00000000000..9cc79a7b129 --- /dev/null +++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr @@ -0,0 +1,15 @@ +warning: trait method `into_iter` will become ambiguous in Rust 2024 + --> $DIR/box-slice-into-iter-ambiguous.rs:24:13 + | +LL | let y = points.into_iter(); + | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyIntoIter::into_iter(points)` + | + = warning: this changes meaning in Rust 2024 +note: the lint level is defined here + --> $DIR/box-slice-into-iter-ambiguous.rs:5:9 + | +LL | #![warn(boxed_slice_into_iter)] + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index 4d968e7bee1..0b1f83a9de9 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -76,8 +76,8 @@ LL | x.cmp(&x); which is required by `&mut dyn T: Iterator` = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `cmp`, perhaps you need to implement one of them: - candidate #1: `Iterator` - candidate #2: `Ord` + candidate #1: `Ord` + = note: the trait `Iterator` defines an item `cmp`, but is explicitly unimplemented error: aborting due to 4 previous errors