Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location: impl NormalizeLocation,
) -> Ty<'tcx> {
let tcx = self.tcx();
let body = self.body;

let cause = ObligationCause::misc(
location.to_locations().span(body),
body.source.def_id().expect_local(),
);

if self.infcx.next_trait_solver() {
let body = self.body;
let param_env = self.infcx.param_env;
// FIXME: Make this into a real type op?
self.fully_perform_op(
Expand All @@ -241,10 +247,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|ocx| {
let structurally_normalize = |ty| {
ocx.structurally_normalize_ty(
&ObligationCause::misc(
location.to_locations().span(body),
body.source.def_id().expect_local(),
),
&cause,
param_env,
ty,
)
Expand All @@ -253,6 +256,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {

let tail = tcx.struct_tail_raw(
ty,
&cause,
structurally_normalize,
|| {},
);
Expand All @@ -265,7 +269,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
} else {
let mut normalize = |ty| self.normalize(ty, location);
let tail = tcx.struct_tail_raw(ty, &mut normalize, || {});
let tail = tcx.struct_tail_raw(ty, &cause, &mut normalize, || {});
normalize(tail)
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
Expand Down Expand Up @@ -196,6 +197,7 @@ fn reconstruct_place_meta<'tcx>(
// Traverse the type, and update `last_valtree` as we go.
let tail = tcx.struct_tail_raw(
layout.ty,
&ObligationCause::dummy(),
|ty| ty,
|| {
let branches = last_valtree.unwrap_branch();
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_hir_typeck/src/expectation.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;

Expand Down Expand Up @@ -74,8 +75,14 @@ impl<'a, 'tcx> Expectation<'tcx> {
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
/// for examples of where this comes up,.
pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
let span = match ty.kind() {
ty::Adt(adt_def, _) => fcx.tcx.def_span(adt_def.did()),
_ => fcx.tcx.def_span(fcx.body_id),
};
let cause = ObligationCause::misc(span, fcx.body_id);

// FIXME: This is not right, even in the old solver...
match fcx.tcx.struct_tail_raw(ty, |ty| ty, || {}).kind() {
match fcx.tcx.struct_tail_raw(ty, &cause, |ty| ty, || {}).kind() {
ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
_ => ExpectHasType(ty),
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if !ty.references_error() {
let tail = self.tcx.struct_tail_raw(
ty,
&self.misc(span),
|ty| {
if self.next_trait_solver() {
self.try_structurally_resolve_type(span, ty)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ pub enum TypeMismatchReason {
#[diag(middle_recursion_limit_reached)]
#[help]
pub(crate) struct RecursionLimitReached<'tcx> {
#[primary_span]
pub span: Span,
pub ty: Ty<'tcx>,
pub suggested_limit: rustc_hir::limit::Limit,
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use {rustc_abi as abi, rustc_hir as hir};

use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::query::TyCtxtAt;
use crate::traits::ObligationCause;
use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt};

Expand Down Expand Up @@ -384,6 +385,7 @@ impl<'tcx> SizeSkeleton<'tcx> {

let tail = tcx.struct_tail_raw(
pointee,
&ObligationCause::dummy(),
|ty| match tcx.try_normalize_erasing_regions(typing_env, ty) {
Ok(ty) => ty,
Err(e) => Ty::new_error_with_message(
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use ty::util::IntTypeExt;

use super::GenericParamDefKind;
use crate::infer::canonical::Canonical;
use crate::traits::ObligationCause;
use crate::ty::InferTy::*;
use crate::ty::{
self, AdtDef, BoundRegionKind, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv,
Expand Down Expand Up @@ -1640,7 +1641,7 @@ impl<'tcx> Ty<'tcx> {
tcx: TyCtxt<'tcx>,
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
) -> Result<Ty<'tcx>, Ty<'tcx>> {
let tail = tcx.struct_tail_raw(self, normalize, || {});
let tail = tcx.struct_tail_raw(self, &ObligationCause::dummy(), normalize, || {});
match tail.kind() {
// Sized types
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use super::TypingEnv;
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir;
use crate::query::Providers;
use crate::traits::ObligationCause;
use crate::ty::layout::{FloatExt, IntegerExt};
use crate::ty::{
self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable,
Expand Down Expand Up @@ -216,7 +217,12 @@ impl<'tcx> TyCtxt<'tcx> {
typing_env: ty::TypingEnv<'tcx>,
) -> Ty<'tcx> {
let tcx = self;
tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(typing_env, ty), || {})
tcx.struct_tail_raw(
ty,
&ObligationCause::dummy(),
|ty| tcx.normalize_erasing_regions(typing_env, ty),
|| {},
)
}

/// Returns true if a type has metadata.
Expand Down Expand Up @@ -248,6 +254,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn struct_tail_raw(
self,
mut ty: Ty<'tcx>,
cause: &ObligationCause<'tcx>,
mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
// This is currently used to allow us to walk a ValTree
// in lockstep with the type in order to get the ValTree branch that
Expand All @@ -261,9 +268,11 @@ impl<'tcx> TyCtxt<'tcx> {
Limit(0) => Limit(2),
limit => limit * 2,
};
let reported = self
.dcx()
.emit_err(crate::error::RecursionLimitReached { ty, suggested_limit });
let reported = self.dcx().emit_err(crate::error::RecursionLimitReached {
span: cause.span,
ty,
suggested_limit,
});
return Ty::new_error(self, reported);
}
match *ty.kind() {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
Some(LangItem::PointeeTrait) => {
let tail = selcx.tcx().struct_tail_raw(
self_ty,
&obligation.cause,
|ty| {
// We throw away any obligations we get from this, since we normalize
// and confirm these obligations once again during confirmation
Expand Down
46 changes: 24 additions & 22 deletions compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_hashes::Hash64;
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::layout::{
FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
};
Expand Down Expand Up @@ -390,30 +391,31 @@ fn layout_of_uncached<'tcx>(

let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
let metadata_ty =
match tcx.try_normalize_erasing_regions(cx.typing_env, pointee_metadata) {
Ok(metadata_ty) => metadata_ty,
Err(mut err) => {
// Usually `<Ty as Pointee>::Metadata` can't be normalized because
// its struct tail cannot be normalized either, so try to get a
// more descriptive layout error here, which will lead to less confusing
// diagnostics.
//
// We use the raw struct tail function here to get the first tail
// that is an alias, which is likely the cause of the normalization
// error.
match tcx.try_normalize_erasing_regions(
cx.typing_env,
tcx.struct_tail_raw(pointee, |ty| ty, || {}),
) {
Ok(_) => {}
Err(better_err) => {
err = better_err;
}
let metadata_ty = match tcx
.try_normalize_erasing_regions(cx.typing_env, pointee_metadata)
{
Ok(metadata_ty) => metadata_ty,
Err(mut err) => {
// Usually `<Ty as Pointee>::Metadata` can't be normalized because
// its struct tail cannot be normalized either, so try to get a
// more descriptive layout error here, which will lead to less confusing
// diagnostics.
//
// We use the raw struct tail function here to get the first tail
// that is an alias, which is likely the cause of the normalization
// error.
match tcx.try_normalize_erasing_regions(
cx.typing_env,
tcx.struct_tail_raw(pointee, &ObligationCause::dummy(), |ty| ty, || {}),
) {
Ok(_) => {}
Err(better_err) => {
err = better_err;
}
return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
}
};
return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
}
};

let metadata_layout = cx.layout_of(metadata_ty)?;
// If the metadata is a 1-zst, then the pointer is thin.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ty_utils/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId)

let tail = tcx.struct_tail_raw(
tcx.type_of(impl_def_id).instantiate_identity(),
&cause,
|ty| {
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
Ty::new_error_with_message(
Expand Down
7 changes: 4 additions & 3 deletions tests/ui/did_you_mean/recursion_limit_deref.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//~ ERROR reached the recursion limit finding the struct tail for `K`
//~| ERROR reached the recursion limit finding the struct tail for `Bottom`

// Test that the recursion limit can be changed and that the compiler
// suggests a fix. In this case, we have a long chain of Deref impls
// which will cause an overflow during the autoderef loop.
Expand All @@ -9,6 +12,7 @@
macro_rules! link {
($outer:ident, $inner:ident) => {
struct $outer($inner);
//~^ ERROR reached the recursion limit finding the struct tail for `Bottom`

impl $outer {
fn new() -> $outer {
Expand Down Expand Up @@ -51,6 +55,3 @@ fn main() {
let x: &Bottom = &t; //~ ERROR mismatched types
//~^ error recursion limit
}

//~? ERROR reached the recursion limit finding the struct tail for `K`
//~? ERROR reached the recursion limit finding the struct tail for `Bottom`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you move from //~? to pointing them at the first line in the file, even though nothing in the output changed? Is the json different and thus suggesting this to be done?

Copy link
Contributor Author

@modhanami modhanami Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was suggested to move //~? to point at the first line in many files. I'm not sure why or whether it is expected.

From rust-log-analyzer

  1. This file: Add span for struct tail recursion limit error #146597 (comment)
  2. Other files: Add span for struct tail recursion limit error #146597 (comment)

18 changes: 15 additions & 3 deletions tests/ui/did_you_mean/recursion_limit_deref.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,28 @@ error: reached the recursion limit finding the struct tail for `Bottom`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`

error: reached the recursion limit finding the struct tail for `Bottom`
--> $DIR/recursion_limit_deref.rs:14:9
|
LL | struct $outer($inner);
| ^^^^^^^^^^^^^^^^^^^^^^
...
LL | link!(A, B);
| ----------- in this macro invocation
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
= note: this error originates in the macro `link` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0055]: reached the recursion limit while auto-dereferencing `J`
--> $DIR/recursion_limit_deref.rs:51:22
--> $DIR/recursion_limit_deref.rs:55:22
|
LL | let x: &Bottom = &t;
| ^^ deref recursion limit reached
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit_deref`)

error[E0308]: mismatched types
--> $DIR/recursion_limit_deref.rs:51:22
--> $DIR/recursion_limit_deref.rs:55:22
|
LL | let x: &Bottom = &t;
| ------- ^^ expected `&Bottom`, found `&Top`
Expand All @@ -25,7 +37,7 @@ LL | let x: &Bottom = &t;
= note: expected reference `&Bottom`
found reference `&Top`

error: aborting due to 4 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0055, E0308.
For more information about an error, try `rustc --explain E0055`.
28 changes: 14 additions & 14 deletions tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
//~ ERROR reached the recursion limit while instantiating `<VirtualWrapper<
//~ ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~| ERROR reached the recursion limit while instantiating `<VirtualWrapper<..., 1> as MyTrait>::virtualize`

//@ build-fail
//@ compile-flags: --diagnostic-width=100 -Zwrite-long-types-to-disk=yes

Expand Down Expand Up @@ -72,16 +85,3 @@ fn main() {
let test = SomeData([0; 256]);
test.virtualize();
}

//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `[u8; 256]`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `SomeData<256>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
//~? ERROR reached the recursion limit finding the struct tail for `VirtualWrapper<SomeData<256>, 0>`
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ error: reached the recursion limit finding the struct tail for `[u8; 256]`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<..., 1>>`
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:18
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:38:18
|
LL | unsafe { virtualize_my_trait(L, self) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -46,7 +46,7 @@ error: reached the recursion limit finding the struct tail for `SomeData<256>`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<..., 1>>`
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:18
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:38:18
|
LL | unsafe { virtualize_my_trait(L, self) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -74,7 +74,7 @@ error: reached the recursion limit finding the struct tail for `VirtualWrapper<S
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<..., 1>>`
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:18
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:38:18
|
LL | unsafe { virtualize_my_trait(L, self) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -85,7 +85,7 @@ LL | unsafe { virtualize_my_trait(L, self) }
error: reached the recursion limit while instantiating `<VirtualWrapper<..., 1> as MyTrait>::virtualize`
|
note: `<VirtualWrapper<T, L> as MyTrait>::virtualize` defined here
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:24:5
--> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:37:5
|
LL | fn virtualize(&self) -> &dyn MyTrait {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
Loading
Loading