Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ty::pretty: prevent infinite recursion for extern crate paths. #89738

Merged
merged 2 commits into from
Oct 17, 2021
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
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, &[]))?;
Copy link
Member

Choose a reason for hiding this comment

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

Reassigning self like this seems somewhat footgunny but looks like its already being done elsewhere…

Copy link
Member Author

Choose a reason for hiding this comment

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

This mess of an API is all "linear" so there's not really any risk - the result has to be used, because a Self value has to be returned, and the call consumes self.


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`.