Skip to content

Commit d2e8ecd

Browse files
committed
Auto merge of rust-lang#121188 - GuillaumeGomez:rollup-bejz7fq, r=GuillaumeGomez
Rollup of 6 pull requests Successful merges: - rust-lang#119928 (suggest `into_iter()` when `Iterator` method called on `impl IntoIterator`) - rust-lang#121020 (Avoid an ICE in diagnostics) - rust-lang#121111 (For E0038, suggest associated type if available) - rust-lang#121137 (Add clippy into the known `cfg` list) - rust-lang#121179 (allow mutable references in const values when they point to no memory) - rust-lang#121181 (Fix an ICE in the recursion lint) r? `@ghost` `@rustbot` modify labels: rollup
2 parents ae9d7b0 + f82875e commit d2e8ecd

File tree

55 files changed

+592
-440
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+592
-440
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
698698
),
699699
..
700700
}) => {
701-
let hir::Ty { span, .. } = inputs[local.index() - 1];
701+
let hir::Ty { span, .. } = *inputs.get(local.index() - 1)?;
702702
Some(span)
703703
}
704704
_ => None,

compiler/rustc_const_eval/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu
453453
const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
454454
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
455455
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
456-
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const` or `static`
456+
const_eval_validation_mutable_ref_in_const_or_static = {$front_matter}: encountered mutable reference in a `const` or `static`
457457
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
458458
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
459459
const_eval_validation_null_box = {$front_matter}: encountered a null box

compiler/rustc_const_eval/src/errors.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -603,18 +603,18 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
603603
PtrToUninhabited { ptr_kind: PointerKind::Box, .. } => {
604604
const_eval_validation_box_to_uninhabited
605605
}
606-
PtrToUninhabited { ptr_kind: PointerKind::Ref, .. } => {
606+
PtrToUninhabited { ptr_kind: PointerKind::Ref(_), .. } => {
607607
const_eval_validation_ref_to_uninhabited
608608
}
609609

610610
PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static,
611-
PtrToStatic { ptr_kind: PointerKind::Ref } => const_eval_validation_ref_to_static,
611+
PtrToStatic { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_ref_to_static,
612612

613613
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
614614
PartialPointer => const_eval_validation_partial_pointer,
615615
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
616616
ConstRefToExtern => const_eval_validation_const_ref_to_extern,
617-
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
617+
MutableRefInConstOrStatic => const_eval_validation_mutable_ref_in_const_or_static,
618618
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
619619
NullFnPtr => const_eval_validation_null_fn_ptr,
620620
NeverVal => const_eval_validation_never_val,
@@ -630,37 +630,39 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
630630
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Box } => {
631631
const_eval_validation_invalid_box_slice_meta
632632
}
633-
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref } => {
633+
InvalidMetaSliceTooLarge { ptr_kind: PointerKind::Ref(_) } => {
634634
const_eval_validation_invalid_ref_slice_meta
635635
}
636636

637637
InvalidMetaTooLarge { ptr_kind: PointerKind::Box } => {
638638
const_eval_validation_invalid_box_meta
639639
}
640-
InvalidMetaTooLarge { ptr_kind: PointerKind::Ref } => {
640+
InvalidMetaTooLarge { ptr_kind: PointerKind::Ref(_) } => {
641641
const_eval_validation_invalid_ref_meta
642642
}
643-
UnalignedPtr { ptr_kind: PointerKind::Ref, .. } => const_eval_validation_unaligned_ref,
643+
UnalignedPtr { ptr_kind: PointerKind::Ref(_), .. } => {
644+
const_eval_validation_unaligned_ref
645+
}
644646
UnalignedPtr { ptr_kind: PointerKind::Box, .. } => const_eval_validation_unaligned_box,
645647

646648
NullPtr { ptr_kind: PointerKind::Box } => const_eval_validation_null_box,
647-
NullPtr { ptr_kind: PointerKind::Ref } => const_eval_validation_null_ref,
649+
NullPtr { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_null_ref,
648650
DanglingPtrNoProvenance { ptr_kind: PointerKind::Box, .. } => {
649651
const_eval_validation_dangling_box_no_provenance
650652
}
651-
DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref, .. } => {
653+
DanglingPtrNoProvenance { ptr_kind: PointerKind::Ref(_), .. } => {
652654
const_eval_validation_dangling_ref_no_provenance
653655
}
654656
DanglingPtrOutOfBounds { ptr_kind: PointerKind::Box } => {
655657
const_eval_validation_dangling_box_out_of_bounds
656658
}
657-
DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref } => {
659+
DanglingPtrOutOfBounds { ptr_kind: PointerKind::Ref(_) } => {
658660
const_eval_validation_dangling_ref_out_of_bounds
659661
}
660662
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Box } => {
661663
const_eval_validation_dangling_box_use_after_free
662664
}
663-
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref } => {
665+
DanglingPtrUseAfterFree { ptr_kind: PointerKind::Ref(_) } => {
664666
const_eval_validation_dangling_ref_use_after_free
665667
}
666668
InvalidBool { .. } => const_eval_validation_invalid_bool,
@@ -766,7 +768,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
766768
}
767769
NullPtr { .. }
768770
| PtrToStatic { .. }
769-
| MutableRefInConst
771+
| MutableRefInConstOrStatic
770772
| ConstRefToMutable
771773
| ConstRefToExtern
772774
| MutableRefToImmutable

compiler/rustc_const_eval/src/interpret/validity.rs

+39-46
Original file line numberDiff line numberDiff line change
@@ -445,22 +445,22 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
445445
// Determine whether this pointer expects to be pointing to something mutable.
446446
let ptr_expected_mutbl = match ptr_kind {
447447
PointerKind::Box => Mutability::Mut,
448-
PointerKind::Ref => {
449-
let tam = value.layout.ty.builtin_deref(false).unwrap();
450-
// ZST never require mutability. We do not take into account interior mutability
451-
// here since we cannot know if there really is an `UnsafeCell` inside
452-
// `Option<UnsafeCell>` -- so we check that in the recursive descent behind this
453-
// reference.
454-
if size == Size::ZERO { Mutability::Not } else { tam.mutbl }
448+
PointerKind::Ref(mutbl) => {
449+
// We do not take into account interior mutability here since we cannot know if
450+
// there really is an `UnsafeCell` inside `Option<UnsafeCell>` -- so we check
451+
// that in the recursive descent behind this reference (controlled by
452+
// `allow_immutable_unsafe_cell`).
453+
mutbl
455454
}
456455
};
457456
// Proceed recursively even for ZST, no reason to skip them!
458457
// `!` is a ZST and we want to validate it.
459458
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) {
459+
let mut skip_recursive_check = false;
460460
// Let's see what kind of memory this points to.
461461
// `unwrap` since dangling pointers have already been handled.
462462
let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id).unwrap();
463-
match alloc_kind {
463+
let alloc_actual_mutbl = match alloc_kind {
464464
GlobalAlloc::Static(did) => {
465465
// Special handling for pointers to statics (irrespective of their type).
466466
assert!(!self.ecx.tcx.is_thread_local_static(did));
@@ -474,12 +474,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
474474
.no_bound_vars()
475475
.expect("statics should not have generic parameters")
476476
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all());
477-
// Mutability check.
478-
if ptr_expected_mutbl == Mutability::Mut {
479-
if !is_mut {
480-
throw_validation_failure!(self.path, MutableRefToImmutable);
481-
}
482-
}
483477
// Mode-specific checks
484478
match self.ctfe_mode {
485479
Some(
@@ -494,42 +488,49 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
494488
// trigger cycle errors if we try to compute the value of the other static
495489
// and that static refers back to us (potentially through a promoted).
496490
// This could miss some UB, but that's fine.
497-
return Ok(());
491+
skip_recursive_check = true;
498492
}
499493
Some(CtfeValidationMode::Const { .. }) => {
500-
// For consts on the other hand we have to recursively check;
501-
// pattern matching assumes a valid value. However we better make
502-
// sure this is not mutable.
503-
if is_mut {
504-
throw_validation_failure!(self.path, ConstRefToMutable);
505-
}
506494
// We can't recursively validate `extern static`, so we better reject them.
507495
if self.ecx.tcx.is_foreign_item(did) {
508496
throw_validation_failure!(self.path, ConstRefToExtern);
509497
}
510498
}
511499
None => {}
512500
}
501+
// Return alloc mutability
502+
if is_mut { Mutability::Mut } else { Mutability::Not }
513503
}
514-
GlobalAlloc::Memory(alloc) => {
515-
if alloc.inner().mutability == Mutability::Mut
516-
&& matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
517-
{
518-
throw_validation_failure!(self.path, ConstRefToMutable);
519-
}
520-
if ptr_expected_mutbl == Mutability::Mut
521-
&& alloc.inner().mutability == Mutability::Not
522-
{
523-
throw_validation_failure!(self.path, MutableRefToImmutable);
524-
}
525-
}
504+
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
526505
GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {
527506
// These are immutable, we better don't allow mutable pointers here.
528-
if ptr_expected_mutbl == Mutability::Mut {
529-
throw_validation_failure!(self.path, MutableRefToImmutable);
530-
}
507+
Mutability::Not
508+
}
509+
};
510+
// Mutability check.
511+
// If this allocation has size zero, there is no actual mutability here.
512+
let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id);
513+
if size != Size::ZERO {
514+
if ptr_expected_mutbl == Mutability::Mut
515+
&& alloc_actual_mutbl == Mutability::Not
516+
{
517+
throw_validation_failure!(self.path, MutableRefToImmutable);
518+
}
519+
if ptr_expected_mutbl == Mutability::Mut
520+
&& self.ctfe_mode.is_some_and(|c| !c.may_contain_mutable_ref())
521+
{
522+
throw_validation_failure!(self.path, MutableRefInConstOrStatic);
523+
}
524+
if alloc_actual_mutbl == Mutability::Mut
525+
&& matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
526+
{
527+
throw_validation_failure!(self.path, ConstRefToMutable);
531528
}
532529
}
530+
// Potentially skip recursive check.
531+
if skip_recursive_check {
532+
return Ok(());
533+
}
533534
}
534535
let path = &self.path;
535536
ref_tracking.track(place, || {
@@ -598,16 +599,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
598599
}
599600
Ok(true)
600601
}
601-
ty::Ref(_, ty, mutbl) => {
602-
if self.ctfe_mode.is_some_and(|c| !c.may_contain_mutable_ref())
603-
&& *mutbl == Mutability::Mut
604-
{
605-
let layout = self.ecx.layout_of(*ty)?;
606-
if !layout.is_zst() {
607-
throw_validation_failure!(self.path, MutableRefInConst);
608-
}
609-
}
610-
self.check_safe_pointer(value, PointerKind::Ref)?;
602+
ty::Ref(_, _ty, mutbl) => {
603+
self.check_safe_pointer(value, PointerKind::Ref(*mutbl))?;
611604
Ok(true)
612605
}
613606
ty::FnPtr(_sig) => {

compiler/rustc_errors/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ pub enum StashKey {
526526
MaybeFruTypo,
527527
CallAssocMethod,
528528
TraitMissingMethod,
529+
AssociatedTypeSuggestion,
529530
OpaqueHiddenTypeMismatch,
530531
MaybeForgetReturn,
531532
/// Query cycle detected, stashing in favor of a better error.

compiler/rustc_hir_typeck/src/method/suggest.rs

+96
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
109109
self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
110110
}
111111

112+
fn impl_into_iterator_should_be_iterator(
113+
&self,
114+
ty: Ty<'tcx>,
115+
span: Span,
116+
unsatisfied_predicates: &Vec<(
117+
ty::Predicate<'_>,
118+
Option<ty::Predicate<'_>>,
119+
Option<ObligationCause<'_>>,
120+
)>,
121+
) -> bool {
122+
fn predicate_bounds_generic_param<'tcx>(
123+
predicate: ty::Predicate<'_>,
124+
generics: &'tcx ty::Generics,
125+
generic_param: &ty::GenericParamDef,
126+
tcx: TyCtxt<'tcx>,
127+
) -> bool {
128+
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
129+
predicate.kind().as_ref().skip_binder()
130+
{
131+
let ty::TraitPredicate { trait_ref: ty::TraitRef { args, .. }, .. } = trait_pred;
132+
if args.is_empty() {
133+
return false;
134+
}
135+
let Some(arg_ty) = args[0].as_type() else {
136+
return false;
137+
};
138+
let ty::Param(param) = arg_ty.kind() else {
139+
return false;
140+
};
141+
// Is `generic_param` the same as the arg for this trait predicate?
142+
generic_param.index == generics.type_param(&param, tcx).index
143+
} else {
144+
false
145+
}
146+
}
147+
148+
fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool {
149+
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
150+
predicate.kind().as_ref().skip_binder()
151+
{
152+
tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
153+
} else {
154+
false
155+
}
156+
}
157+
158+
// Does the `ty` implement `IntoIterator`?
159+
let Some(into_iterator_trait) = self.tcx.get_diagnostic_item(sym::IntoIterator) else {
160+
return false;
161+
};
162+
let trait_ref = ty::TraitRef::new(self.tcx, into_iterator_trait, [ty]);
163+
let cause = ObligationCause::new(span, self.body_id, ObligationCauseCode::MiscObligation);
164+
let obligation = Obligation::new(self.tcx, cause, self.param_env, trait_ref);
165+
if !self.predicate_must_hold_modulo_regions(&obligation) {
166+
return false;
167+
}
168+
169+
match ty.kind() {
170+
ty::Param(param) => {
171+
let generics = self.tcx.generics_of(self.body_id);
172+
let generic_param = generics.type_param(&param, self.tcx);
173+
for unsatisfied in unsatisfied_predicates.iter() {
174+
// The parameter implements `IntoIterator`
175+
// but it has called a method that requires it to implement `Iterator`
176+
if predicate_bounds_generic_param(
177+
unsatisfied.0,
178+
generics,
179+
generic_param,
180+
self.tcx,
181+
) && is_iterator_predicate(unsatisfied.0, self.tcx)
182+
{
183+
return true;
184+
}
185+
}
186+
}
187+
ty::Alias(ty::AliasKind::Opaque, _) => {
188+
for unsatisfied in unsatisfied_predicates.iter() {
189+
if is_iterator_predicate(unsatisfied.0, self.tcx) {
190+
return true;
191+
}
192+
}
193+
}
194+
_ => return false,
195+
}
196+
false
197+
}
198+
112199
#[instrument(level = "debug", skip(self))]
113200
pub fn report_method_error(
114201
&self,
@@ -555,6 +642,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
555642
"`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
556643
));
557644
}
645+
} else if self.impl_into_iterator_should_be_iterator(rcvr_ty, span, unsatisfied_predicates)
646+
{
647+
err.span_label(span, format!("`{rcvr_ty}` is not an iterator"));
648+
err.multipart_suggestion_verbose(
649+
"call `.into_iter()` first",
650+
vec![(span.shrink_to_lo(), format!("into_iter()."))],
651+
Applicability::MaybeIncorrect,
652+
);
653+
return Some(err);
558654
} else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
559655
// We special case the situation where we are looking for `_` in
560656
// `<TypeParam as _>::method` because otherwise the machinery will look for blanket

compiler/rustc_middle/src/mir/interpret/error.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_macros::HashStable;
1212
use rustc_session::CtfeBacktrace;
1313
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
1414
use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
15+
use rustc_type_ir::Mutability;
1516

1617
use std::borrow::Cow;
1718
use std::{any::Any, backtrace::Backtrace, fmt};
@@ -367,15 +368,15 @@ pub enum UndefinedBehaviorInfo<'tcx> {
367368

368369
#[derive(Debug, Clone, Copy)]
369370
pub enum PointerKind {
370-
Ref,
371+
Ref(Mutability),
371372
Box,
372373
}
373374

374375
impl IntoDiagnosticArg for PointerKind {
375376
fn into_diagnostic_arg(self) -> DiagnosticArgValue {
376377
DiagnosticArgValue::Str(
377378
match self {
378-
Self::Ref => "ref",
379+
Self::Ref(_) => "ref",
379380
Self::Box => "box",
380381
}
381382
.into(),
@@ -408,7 +409,7 @@ impl From<PointerKind> for ExpectedKind {
408409
fn from(x: PointerKind) -> ExpectedKind {
409410
match x {
410411
PointerKind::Box => ExpectedKind::Box,
411-
PointerKind::Ref => ExpectedKind::Reference,
412+
PointerKind::Ref(_) => ExpectedKind::Reference,
412413
}
413414
}
414415
}
@@ -419,7 +420,7 @@ pub enum ValidationErrorKind<'tcx> {
419420
PartialPointer,
420421
PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
421422
PtrToStatic { ptr_kind: PointerKind },
422-
MutableRefInConst,
423+
MutableRefInConstOrStatic,
423424
ConstRefToMutable,
424425
ConstRefToExtern,
425426
MutableRefToImmutable,

0 commit comments

Comments
 (0)