Skip to content

Commit 59dc218

Browse files
authored
Rollup merge of #89738 - eddyb:extern-crate-recursion, r=nagisa
ty::pretty: prevent infinite recursion for `extern crate` paths. Fixes #55779, fixes #87932. This fix is based on `@estebank's` idea in #55779 (comment) - but instead of trying to get `try_print_visible_def_path_recur`'s cycle detection to work in this case, this PR "just" disables the "visible path" feature when printing the path to an `extern crate`, so that the old recursion chain of `try_print_visible_def_path -> print_def_path -> try_print_visible_def_path`, is now impossible. Both tests have been confirmed to crash `rustc` because of a stack overflow, without the fix.
2 parents 6f53ddf + f14e8dd commit 59dc218

File tree

6 files changed

+84
-10
lines changed

6 files changed

+84
-10
lines changed

compiler/rustc_middle/src/ty/print/pretty.rs

+18-10
Original file line numberDiff line numberDiff line change
@@ -350,18 +350,26 @@ pub trait PrettyPrinter<'tcx>:
350350
match self.tcx().extern_crate(def_id) {
351351
Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
352352
(ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
353-
debug!("try_print_visible_def_path: def_id={:?}", def_id);
354-
return Ok((
355-
if !span.is_dummy() {
356-
self.print_def_path(def_id, &[])?
357-
} else {
358-
self.path_crate(cnum)?
359-
},
360-
true,
361-
));
353+
// NOTE(eddyb) the only reason `span` might be dummy,
354+
// that we're aware of, is that it's the `std`/`core`
355+
// `extern crate` injected by default.
356+
// FIXME(eddyb) find something better to key this on,
357+
// or avoid ending up with `ExternCrateSource::Extern`,
358+
// for the injected `std`/`core`.
359+
if span.is_dummy() {
360+
return Ok((self.path_crate(cnum)?, true));
361+
}
362+
363+
// Disable `try_print_trimmed_def_path` behavior within
364+
// the `print_def_path` call, to avoid infinite recursion
365+
// in cases where the `extern crate foo` has non-trivial
366+
// parents, e.g. it's nested in `impl foo::Trait for Bar`
367+
// (see also issues #55779 and #87932).
368+
self = with_no_visible_paths(|| self.print_def_path(def_id, &[]))?;
369+
370+
return Ok((self, true));
362371
}
363372
(ExternCrateSource::Path, LOCAL_CRATE) => {
364-
debug!("try_print_visible_def_path: def_id={:?}", def_id);
365373
return Ok((self.path_crate(cnum)?, true));
366374
}
367375
_ => {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub trait Trait { fn no_op(&self); }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub trait Deserialize {
2+
fn deserialize();
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// run-pass
2+
// edition:2018
3+
// aux-crate:issue_55779_extern_trait=issue-55779-extern-trait.rs
4+
5+
use issue_55779_extern_trait::Trait;
6+
7+
struct Local;
8+
struct Helper;
9+
10+
impl Trait for Local {
11+
fn no_op(&self)
12+
{
13+
// (Unused) extern crate declaration necessary to reproduce bug
14+
extern crate issue_55779_extern_trait;
15+
16+
// This one works
17+
// impl Trait for Helper { fn no_op(&self) { } }
18+
19+
// This one infinite-loops
20+
const _IMPL_SERIALIZE_FOR_HELPER: () = {
21+
// (extern crate can also appear here to reproduce bug,
22+
// as in originating example from serde)
23+
impl Trait for Helper { fn no_op(&self) { } }
24+
};
25+
26+
}
27+
}
28+
29+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// edition:2018
2+
// aux-crate:issue_87932_a=issue-87932-a.rs
3+
4+
pub struct A {}
5+
6+
impl issue_87932_a::Deserialize for A {
7+
fn deserialize() {
8+
extern crate issue_87932_a as _a;
9+
}
10+
}
11+
12+
fn main() {
13+
A::deserialize();
14+
//~^ ERROR no function or associated item named `deserialize` found for struct `A`
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0599]: no function or associated item named `deserialize` found for struct `A` in the current scope
2+
--> $DIR/issue-87932.rs:13:8
3+
|
4+
LL | pub struct A {}
5+
| ------------ function or associated item `deserialize` not found for this
6+
...
7+
LL | A::deserialize();
8+
| ^^^^^^^^^^^ function or associated item not found in `A`
9+
|
10+
= help: items from traits can only be used if the trait is in scope
11+
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
12+
|
13+
LL | use <crate::A as issue_87932_a::Deserialize>::deserialize::_a::Deserialize;
14+
|
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)