diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6fd509ed32f..c03eeb1790e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2942,7 +2942,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - self.autoderef(span, base_ty) + let mut autoderef = self.autoderef(span, base_ty).silence_errors(); + let deref_chain: Vec<_> = autoderef.by_ref().collect(); + + // Don't probe if we hit the recursion limit, since it may result in + // quadratic blowup if we then try to further deref the results of this + // function. This is a best-effort method, after all. + if autoderef.reached_recursion_limit() { + return vec![]; + } + + deref_chain + .into_iter() .filter_map(move |(base_t, _)| { match base_t.kind() { ty::Adt(base_def, args) if !base_def.is_enum() => { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3ba3429cbb3..5dc341653e5 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If our autoderef loop had reached the recursion limit, // report an overflow error, but continue going on with // the truncated autoderef list. - if steps.reached_recursion_limit { + if steps.reached_recursion_limit && !is_suggestion.0 { self.probe(|_| { let ty = &steps .steps diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9ede809ead2..207cf4686b6 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -672,7 +672,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut ty_str_reported = ty_str.clone(); if let ty::Adt(_, generics) = rcvr_ty.kind() { if generics.len() > 0 { - let mut autoderef = self.autoderef(span, rcvr_ty); + let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors(); let candidate_found = autoderef.any(|(ty, _)| { if let ty::Adt(adt_def, _) = ty.kind() { self.tcx diff --git a/tests/ui/methods/probe-error-on-infinite-deref.rs b/tests/ui/methods/probe-error-on-infinite-deref.rs new file mode 100644 index 00000000000..c671092e6aa --- /dev/null +++ b/tests/ui/methods/probe-error-on-infinite-deref.rs @@ -0,0 +1,17 @@ +use std::ops::Deref; + +// Make sure that method probe error reporting doesn't get too tangled up +// on this infinite deref impl. See #130224. + +struct Wrap(T); +impl Deref for Wrap { + type Target = Wrap>; + fn deref(&self) -> &Wrap> { todo!() } +} + +fn main() { + Wrap(1).lmao(); + //~^ ERROR reached the recursion limit + //~| ERROR reached the recursion limit + //~| ERROR no method named `lmao` +} diff --git a/tests/ui/methods/probe-error-on-infinite-deref.stderr b/tests/ui/methods/probe-error-on-infinite-deref.stderr new file mode 100644 index 00000000000..0d416a71222 --- /dev/null +++ b/tests/ui/methods/probe-error-on-infinite-deref.stderr @@ -0,0 +1,30 @@ +error[E0055]: reached the recursion limit while auto-dereferencing `Wrap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/probe-error-on-infinite-deref.rs:13:13 + | +LL | Wrap(1).lmao(); + | ^^^^ deref recursion limit reached + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`probe_error_on_infinite_deref`) + +error[E0055]: reached the recursion limit while auto-dereferencing `Wrap>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/probe-error-on-infinite-deref.rs:13:13 + | +LL | Wrap(1).lmao(); + | ^^^^ deref recursion limit reached + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`probe_error_on_infinite_deref`) + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0599]: no method named `lmao` found for struct `Wrap<{integer}>` in the current scope + --> $DIR/probe-error-on-infinite-deref.rs:13:13 + | +LL | struct Wrap(T); + | -------------- method `lmao` not found for this struct +... +LL | Wrap(1).lmao(); + | ^^^^ method not found in `Wrap<{integer}>` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0055, E0599. +For more information about an error, try `rustc --explain E0055`.