rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.98k stars 12.79k forks source link

`extern crate` not in the root module is just a weird use and should be linted against. #115227

Open CAD97 opened 1 year ago

CAD97 commented 1 year ago

Outside of the root module, edition2018+ (path reform) extern crate still behaves like edition2015 extern crate — that is, it doesn't make the name available as ::cratename, only importing it as self::cratename as with any other use. Replacing $vis extern crate $krate $(as $name)?; with $vis use ::$krate $(as $name)?; is much less confusing and is perfectly semantics-preserving except for sysroot crates (crates available to extern crate but not in the extern prelude by default, e.g. alloc) and extern crate self (which is equivalent to $vis use crate $(as $name)?; instead).

Even the case where the extern crate is pulling in a sysroot crate not already pulled into the ::cratename namespace would be more clearly written with an extern crate in the root module and a use in the nonroot namespace.

Example: [playground]

fn test() {
    extern crate alloc;

    ::alloc::vec![0]; // error failed to resolve
    alloc::vec![0]; // okay
}

This behavior is odd and unnecessary enough (just use use) that it might be worth considering making extern crate an error when not at the crate root in future editions. The only reason to keep it IMHO is the different errors between extern crate notacrate; and use ::notacrate;, where the former might be preferable for macro "peer dependencies" expecting the user to have some crate dependency available.

bjorn3 commented 1 year ago

serde_derive does this inside an const _: () = { ... }; block to import serde inside the macro expansion. Using use ::serde as _serde doesn't work because it still uses the 2015 edition.