Auto merge of #124097 - compiler-errors:box-into-iter, r=WaffleLapkin

Add `IntoIterator` for `Box<[T]>` + edition 2024-specific lints

* Adds a similar method probe opt-out mechanism to the `[T;N]: IntoIterator` implementation for edition 2021.
* Adjusts the relevant lints (shadowed `.into_iter()` calls, new source of method ambiguity).
* Adds some tests.
* Took the liberty to rework the logic in the `ARRAY_INTO_ITER` lint, since it was kind of confusing.

Based mostly off of #116607.

ACP: rust-lang/libs-team#263
References #59878
Tracking for Rust 2024: https://github.com/rust-lang/rust/issues/123759

Crater run was done here: https://github.com/rust-lang/rust/pull/116607#issuecomment-1770293013
Consensus afaict was that there is too much breakage, so let's do this in an edition-dependent way much like `[T; N]: IntoIterator`.
This commit is contained in:
bors 2024-05-21 10:13:53 +00:00
commit e8fbd99128
37 changed files with 688 additions and 247 deletions

View File

@ -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()
}
}

View File

@ -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, ..."),

View File

@ -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,

View File

@ -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);

View File

@ -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(

View File

@ -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(

View File

@ -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

View File

@ -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: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
};
}
#[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 },
);
}
}
}

View File

@ -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,

View File

@ -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<ArrayIntoIterDiagSub>,
pub sub: Option<ShadowedIntoIterDiagSub>,
}
#[derive(Subdiagnostic)]
pub enum ArrayIntoIterDiagSub {
pub enum ShadowedIntoIterDiagSub {
#[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
RemoveIntoIter {
#[primary_span]

View File

@ -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: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
};
}
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 },
);
}
}

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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<Vec<Ident>>,
pub implement_via_object: bool,

View File

@ -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<I> FromIterator<I> 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<I, A: Allocator> !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<I, A: Allocator> IntoIterator for Box<[I], A> {
type IntoIter = vec::IntoIter<I, A>;
type Item = I;
fn into_iter(self) -> vec::IntoIter<I, A> {
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<char> for Box<str> {

View File

@ -38,7 +38,7 @@ pub struct IntoIter<T, const N: usize> {
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")]

View File

@ -268,7 +268,6 @@ where
/// }
/// ```
#[rustc_diagnostic_item = "IntoIterator"]
#[rustc_skip_array_during_method_dispatch]
#[rustc_on_unimplemented(
on(
_Self = "core::ops::range::RangeTo<Idx>",
@ -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.

View File

@ -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<T> !Iterator for [T] {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> IntoIterator for &'a [T] {
type Item = &'a T;

View File

@ -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()

View File

@ -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()

View File

@ -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::<i32, _>(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::<i32>::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::<i32>::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::<i32, u64>::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::<i32, u64>::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::<i32>::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::<i32>::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::<i32>::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::<i32>::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::<i32, u64>::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::<i32, u64>::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::<i32>::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::<i32>::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::<i32>::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

View File

@ -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
}

View File

@ -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();

View File

@ -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];

View File

@ -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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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() {}

View File

@ -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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
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();

View File

@ -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<i32> = 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
}
}

View File

@ -0,0 +1,60 @@
warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> 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 `<Box<[T]> 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 `<Box<[T]> 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 `<Box<[T]> 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 `<Box<[T]> 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

View File

@ -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<i32> = boxed_slice.clone().into_iter();
// And through other boxes.
let _: IntoIter<i32> = Box::new(boxed_slice.clone()).into_iter();
// You can always use the trait method explicitly as a boxed_slice.
let _: IntoIter<i32> = IntoIterator::into_iter(boxed_slice.clone());
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -0,0 +1,35 @@
warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> 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 `<Box<[T]> 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 `<Box<[T]> 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

View File

@ -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<T> 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
}

View File

@ -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<T> 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
}

View File

@ -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

View File

@ -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