Skip to content

Lint when shadowing a glob-reexported item with a local declaration  #111336

Closed

Description

Code

mod inner {
    pub struct Foo {};
}

mod other {
    struct Foo;
}

pub use inner::*;

// Adding either of the following two lines
// would shadow `inner::Foo` and
// hide the name `Foo` from the public API.
//
// (1)
// struct Foo;
//
// (2)
// use other::Foo;

Current output

compiles without errors, warnings, or clippy lints

Desired output

struct Foo;
^^^^^^^^^^
shadows `Foo` re-exported from `pub use inner::*`
note: the shadowing prevents `Foo` from being exported by this module, which may break downstream uses

***

use other::Foo;
           ^^^
           shadows `Foo` re-exported from `pub use inner::*`
note: the shadowing prevents `Foo` from being exported by this module, which may break downstream uses

Rationale and extra context

Similar to #107563

Whereas that issue tackled the case of glob-glob name conflicts, this issue is about glob-vs-local name conflicts in which case the local name shadows the one imported from the glob. This is a footgun and can lead to semver-major breaking changes: uncommenting either line (1) or (2) in the code example above is a major breaking change for the containing crate, since it causes the name Foo to stop being exported and makes Foo become an unnamable (Voldemort) type.

This is not a hypothetical issue. Around a year ago, the opencl3 crate seems to have suffered a regression when a large number of its items were accidentally shadowed. Neither code review nor tests seem to have been effective at preventing the regression. The fixing PR for that regression adds a test for the public re-export of one of the affected items.

This seems like a perfect situation for a lint. Shadowing a glob-reexported item with a local declaration is pretty much never what you want. If you wanted an unnamable type, there's a better way, and if you didn't want the item to be reexported then tweak the module structure so it doesn't get reexported.

I plan to publish a blog post with more details about this in a few hours, it will be available at the following link: https://predr.ag/blog/breaking-semver-in-rust-by-adding-private-type-or-import/

Other cases

No response

Anything else?

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

A-lintArea: Lints (warnings about flaws in source code) such as unused_mut.A-resolveArea: Name resolutionT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions