Skip to content

Commit

Permalink
Rollup merge of #89738 - eddyb:extern-crate-recursion, r=nagisa
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
matthiaskrgr authored Oct 17, 2021
2 parents 6f53ddf + f14e8dd commit 59dc218
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 10 deletions.
28 changes: 18 additions & 10 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,18 +350,26 @@ pub trait PrettyPrinter<'tcx>:
match self.tcx().extern_crate(def_id) {
Some(&ExternCrate { src, dependency_of, span, .. }) => match (src, dependency_of) {
(ExternCrateSource::Extern(def_id), LOCAL_CRATE) => {
debug!("try_print_visible_def_path: def_id={:?}", def_id);
return Ok((
if !span.is_dummy() {
self.print_def_path(def_id, &[])?
} else {
self.path_crate(cnum)?
},
true,
));
// NOTE(eddyb) the only reason `span` might be dummy,
// that we're aware of, is that it's the `std`/`core`
// `extern crate` injected by default.
// FIXME(eddyb) find something better to key this on,
// or avoid ending up with `ExternCrateSource::Extern`,
// for the injected `std`/`core`.
if span.is_dummy() {
return Ok((self.path_crate(cnum)?, true));
}

// Disable `try_print_trimmed_def_path` behavior within
// the `print_def_path` call, to avoid infinite recursion
// in cases where the `extern crate foo` has non-trivial
// parents, e.g. it's nested in `impl foo::Trait for Bar`
// (see also issues #55779 and #87932).
self = with_no_visible_paths(|| self.print_def_path(def_id, &[]))?;

return Ok((self, true));
}
(ExternCrateSource::Path, LOCAL_CRATE) => {
debug!("try_print_visible_def_path: def_id={:?}", def_id);
return Ok((self.path_crate(cnum)?, true));
}
_ => {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub trait Trait { fn no_op(&self); }
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub trait Deserialize {
fn deserialize();
}
29 changes: 29 additions & 0 deletions src/test/ui/rust-2018/uniform-paths/issue-55779.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// run-pass
// edition:2018
// aux-crate:issue_55779_extern_trait=issue-55779-extern-trait.rs

use issue_55779_extern_trait::Trait;

struct Local;
struct Helper;

impl Trait for Local {
fn no_op(&self)
{
// (Unused) extern crate declaration necessary to reproduce bug
extern crate issue_55779_extern_trait;

// This one works
// impl Trait for Helper { fn no_op(&self) { } }

// This one infinite-loops
const _IMPL_SERIALIZE_FOR_HELPER: () = {
// (extern crate can also appear here to reproduce bug,
// as in originating example from serde)
impl Trait for Helper { fn no_op(&self) { } }
};

}
}

fn main() { }
15 changes: 15 additions & 0 deletions src/test/ui/rust-2018/uniform-paths/issue-87932.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// edition:2018
// aux-crate:issue_87932_a=issue-87932-a.rs

pub struct A {}

impl issue_87932_a::Deserialize for A {
fn deserialize() {
extern crate issue_87932_a as _a;
}
}

fn main() {
A::deserialize();
//~^ ERROR no function or associated item named `deserialize` found for struct `A`
}
18 changes: 18 additions & 0 deletions src/test/ui/rust-2018/uniform-paths/issue-87932.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0599]: no function or associated item named `deserialize` found for struct `A` in the current scope
--> $DIR/issue-87932.rs:13:8
|
LL | pub struct A {}
| ------------ function or associated item `deserialize` not found for this
...
LL | A::deserialize();
| ^^^^^^^^^^^ function or associated item not found in `A`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
LL | use <crate::A as issue_87932_a::Deserialize>::deserialize::_a::Deserialize;
|

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.

0 comments on commit 59dc218

Please sign in to comment.