Skip to content

Conversation

@Voultapher
Copy link
Contributor

@Voultapher Voultapher commented Apr 7, 2025

Currently all core and std macros are automatically added to the prelude via #[macro_use]. However a situation arose where we want to add a new macro assert_matches but don't want to pull it into the standard prelude for compatibility reasons. By explicitly exporting the macros found in the core and std crates we get to decide on a per macro basis and can later add them via the rust_20xx preludes.

Closes #53977
Unlocks #137487

Reference PR:

Stabilization report:

@rustbot
Copy link
Collaborator

rustbot commented Apr 7, 2025

r? @ChrisDenton

rustbot has assigned @ChrisDenton.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Apr 7, 2025
@Voultapher
Copy link
Contributor Author

r? @Amanieu

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Voultapher
Copy link
Contributor Author

@Amanieu the tidy issue highlights an annoying and unforeseen side-effect of this change. The vec module is now part of the prelude. In effect this means that for example this code:

fn xx(i: vec::IntoIter<i32>) {
    let _ = i.as_slice();
}

fn main() {}

that currently doesn't compile on stable would now compile. Initially I thought this would cause name collisions if users define their own vec module but so far I wasn't able to produce those, it seems to always prefer the local module. But regardless, I think we don't want to allow access to a standard library namespace without going through std, alloc or core. AFAIK there is no way to pub use only the macro and not the module namespace without modifications. I have two ideas how to tackle this, maybe we can rename vec to vec_xx internally and have separate use expressions or we have to add another crate that we can #[macro_use] inject into the prelude that only contains the vec macro. Thoughts?

@traviscross
Copy link
Contributor

@petrochenkov
Copy link
Contributor

There's an issue for this change - #53977.

@dtolnay
Copy link
Member

dtolnay commented Apr 8, 2025

@Voultapher, avoiding the vec module re-export can be done like this:

#[macro_export]
macro_rules! myvec {
    () => {};
}

pub mod myvec {
    pub struct Vec;
}

pub mod prelude {
    // Bad: re-exports both macro and type namespace
    // pub use crate::myvec;
    
    mod vec_macro_only {
        #[allow(hidden_glob_reexports)]
        mod myvec {}
        pub use crate::*;
    }
    pub use self::vec_macro_only::myvec;
}

fn main() {
    prelude::myvec!();
    let _: prelude::myvec::Vec; // error
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=5e50828c593e04ba0e98f48c9d8696b4

@Voultapher
Copy link
Contributor Author

I've applied the suggestion by @dtolnay local tests seem promising. @Kobzol could we please do a timer run to see if this PR impacts compile-times.

@petrochenkov
Copy link
Contributor

env and panic (and maybe something else now?) need to be treated in the same way as vec.

@rust-log-analyzer

This comment has been minimized.

@Kobzol
Copy link
Member

Kobzol commented Apr 8, 2025

@Voultapher Based on the CI failure I think that a try build would fail now.

@Voultapher
Copy link
Contributor Author

Ok, I'll try to get the CI passing first.

@Voultapher
Copy link
Contributor Author

@petrochenkov I went through all macros and searched the docs and env and panic seem to be the only other ones affected.

@rust-log-analyzer

This comment has been minimized.

@Voultapher
Copy link
Contributor Author

@Amanieu this program previously worked:

use std::*;

fn main() {
    panic!("panic works")
}

and now runs into:

error[E0659]: `panic` is ambiguous
   --> src/main.rs:4:5
    |
4   |     panic!("panic works")
    |     ^^^^^ ambiguous name
    |
    = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
note: `panic` could refer to the macro imported here
   --> src/main.rs:1:5
    |
1   | use std::*;
    |     ^^^^^^
    = help: consider adding an explicit import of `panic` to disambiguate
    = help: or use `crate::panic` to refer to this macro unambiguously
note: `panic` could also refer to the macro defined here
   --> rust/library/std/src/prelude/mod.rs:157:13
    |
157 |     pub use super::v1::*;
    |             ^^^^^^^^^

I don't see how we can resolve that without changing language import rules and or special casing the prelude import.

@Amanieu
Copy link
Member

Amanieu commented Apr 9, 2025

@petrochenkov Do you have any ideas about that?

@petrochenkov petrochenkov self-assigned this Apr 9, 2025
@petrochenkov
Copy link
Contributor

Could you add a test making sure that the modules vec, env and panic are not in prelude?

@petrochenkov
Copy link
Contributor

@petrochenkov Do you have any ideas about that?

The ambiguity wouldn't happen if it was the same panic in std root and in the stdlib prelude.
However, std and core have two different panic macros.

Previously #[macro_use] extern crate std; would add the std's panic to macro_use prelude, and #[macro_use] extern crate core; would add the core's panic.
This PR always adds the core's panic.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 10, 2025
@craterbot craterbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 24, 2025
@petrochenkov
Copy link
Contributor

Significant regressions:

  • themasch.rust-jvm.2d7418c568670d8bcc52ef7e64cc0704f9c34eb1 - dbg! is ambiguous (glob import of custom dbg vs prelude)
  • dmidecode-1.0.0 - assert_eq! is ambiguous (manual glob import from prelude vs macro-expanded single import of custom partial_eq from pretty_assertions)
  • gcode-0.6.1 - assert_eq! is ambiguous (manual glob import from prelude vs macro_use of custom partial_eq from pretty_assertions)
  • threescalers-0.8.0 - matches! is ambiguous (manual glob import from prelude vs custom matches)
  • ipcrypt-0.1.0 - cannot find macro assert_eq due to no_implicit_prelude

Insignificant regressions:

  • cometbft-config-0.1.0-alpha.2 - ambiguous_panic_imports with denied lints
  • deranged-0.5.4 - ambiguous_panic_imports with denied lints
  • tendermint-config-0.40.4 - ambiguous_panic_imports with denied lints
  • playdate-* crates - uses format_args_nl (unstable feature)
  • thescribe11.Rust-SST.3765b213d621b25f400804842a040ed5916fb048 - uses format_args_nl (unstable feature)
  • berkus.mre-write_to.f0dca907fc0573b643ad076f12c3f0515665cabf - uses format_args_nl (unstable feature)

@petrochenkov
Copy link
Contributor

Looks good enough to me, if you send fixes to the crates from the "significant" category.

Could you also write a more detailed proposal / change description for this change, so I could send it to language and library teams for formal approval?
@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 24, 2025
@bors
Copy link
Collaborator

bors commented Oct 29, 2025

☔ The latest upstream changes (presumably #148208) made this pull request unmergeable. Please resolve the merge conflicts.

@PoignardAzur
Copy link
Contributor

PoignardAzur commented Nov 5, 2025

Fixing the relevant crates sounds easy enough. I'll see if I can make progress.

@Voultapher
Copy link
Contributor Author

@PoignardAzur I have some time Friday and had planned on tackling it then, how about we split the work?

PoignardAzur added a commit to PoignardAzur/gcode-rs that referenced this pull request Nov 5, 2025
These uses of assert_eq will be broken by changes to how the prelude handles macros: rust-lang/rust#139493.
PoignardAzur added a commit to PoignardAzur/rust-ipcrypt that referenced this pull request Nov 5, 2025
These uses of assert_eq will be broken by changes to how the prelude handles macros: rust-lang/rust#139493.
@PoignardAzur
Copy link
Contributor

PoignardAzur commented Nov 5, 2025

Well, too late, I've done most of it.

Some notes:

Overall I don't think this PR needs to wait on any of the crates listed in the crater report except maybe threescalers. There is virtually no chance that a crate sees one of its dependencies stop working because of this PR (aside from maybe playdate dependents, but those are on nightly).

@unleashed
Copy link
Contributor

Overall I don't think this PR needs to wait on any of the crates listed in the crater report except maybe threescalers. There is virtually no chance that a crate sees one of its dependencies stop working because of this PR (aside from maybe playdate dependents, but those are on nightly).

threescalers maintainer here. Don't wait on this crate either as all known users either use older toolchains and are very slow to update or point to a recent git revision. I'll be releasing an update this week to crates.io to fix this, but no need to wait.

@Voultapher
Copy link
Contributor Author

@PoignardAzur wonderful, thanks for the help.

@Voultapher
Copy link
Contributor Author

Voultapher commented Nov 7, 2025

@petrochenkov A more detailed change description as discussion basis for the lang team:


This change if merged would change the code injected into user crates to no longer include #[macro_use] on extern crate core and extern crate std. This change is motivated by a near term goal and a longer term goal. The near term goal is to allow a macro to be defined at the std or core crate root but not have it be part of the implicit prelude. Such macros can then be separately promoted to the prelude in a new edition. Specifically this is blocking the stabilization of assert_matches #137487. The longer term goal is to gradually deprecate #[macro_use]. By no longer requiring it for standard library usage, this serves as a step towards that goal. For more information see #53977. Currently, prelude macros have a higher priority than glob-imported macros. This causes a previously silent ambiguity to become an error. A minimal example:

#![no_std]

extern crate std;
use std::prelude::v1::*;

fn xx() {
    panic!(); // resolves to core::panic
}

This resolution is surprising or at least not obvious. It's possible for user code to invoke this ambiguity by defining their own macros with standard library names and glob importing them, e.g. use nom::* importing nom::dbg. In practice this happens rarely based on crater data. The 3 public crates where this was an issue, have been fixed. The ambiguous panic import is more common and affects a non-trivial amount of the public - and likely private - crate ecosystem. To avoid a breaking change, a new future incompatible lint was added ambiguous_panic_imports see #147319. This allows current code to continue compiling, albeit with a new warning. Future editions of Rust make this an error and future versions of Rust can choose to make this error. Technically this is a breaking change, but crater gives us the confidence that the impact will be at worst a new warning for 99+% of public and private crates.


There are some side-effect changes like no longer exporting format_args_nl but I'm not listing them since they aren't relevant to the bigger picture. Please let me know if this is what you had in mind and works for the intended purpose.

@traviscross traviscross added the needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. label Nov 8, 2025
@traviscross
Copy link
Contributor

Thanks for that overview.

Please let me know if this is what you had in mind and works for the intended purpose.

See our lang stabilization report template.

@Voultapher
Copy link
Contributor Author

If you want I can fill out that template, but I doubt it would be all that helpful since hardly any point applies to this change.

This change is closer to an implementation detail than a classical language feature.

@traviscross
Copy link
Contributor

The main parts that seem worthwhile are:

  • Reference: You'll want to confirm whether anything in the Reference needs to change (or whether it was already silent on this point, and this change makes it more correct).
  • What is stabilized: In addition to the breaking change, this PR adds a new lint. This should be described more specifically (lang approves new lints via FCP as well).
  • Tool changes: You'll want to confirm for us that this doesn't have any effects we need to consider on our other tools.
  • Breaking changes: You covered this, but this aspect will get a lot of attention, so any quantitative or qualitative details and examples you can add to give context to the scope of the breakage we're accepting and also the scope of what we'd be covering with the FCW (and hoping to break later) would be helpful.

Regarding the FCW, typically we've been setting that to report in deps at the same time that we make it deny-by-default (i.e., we move from warn / no-report-in-deps to deny / report-in-deps atomically). Perhaps that makes sense here too; talk about whether starting at deny-by-default would be too much.

Regarding where you said:

There are some side-effect changes like no longer exporting format_args_nl but I'm not listing them since they aren't relevant to the bigger picture.

Tell us the details. The big picture is good, but we all want to see discussion of all consequences you know of.

@Voultapher
Copy link
Contributor Author

Voultapher commented Nov 8, 2025

  • Reference: Good point it does indeed need changing. I've created a PR for that Reflect explicit macro import in reference reference#2077

  • Stabilization:

    • #[macro_use] is no longer automatically included in the crate root module. This allows the explicit import of macros in the core and std prelude e.g. pub use crate::dbg;. No code that was previously not accepted will be accepted now.

    • ambiguous_panic_imports lint. No code that was previously not accepted will be accepted now. Code that previously passed without warnings, but included the following or equivalent - only pertaining to core vs std panic - will now receive a warning:

      #![no_std]
      
      extern crate std;
      use std::prelude::v1::*;
      
      fn xx() {
          panic!(); // resolves to core::panic
          //~^ WARNING `panic` is ambiguous
          //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
      }
  • Tool changes: To my knowledge no tool changes are necessary and I'm not aware of issues created in other tools by this change. It's possible that external tools make assumptions that will be broken by this. There has been extensive testing as part of the CI giving us confidence that at least our internal tooling isn't broken by this.

  • Breaking changes:

    • It's possible for user code to invoke an ambiguity by defining their own macros with standard library names and glob importing them, e.g. use nom::* importing nom::dbg. In practice this happens rarely based on crater data. The 3 public crates where this was an issue, have been fixed. The ambiguous panic import is more common and affects a non-trivial amount of the public - and likely private - crate ecosystem. To avoid a breaking change, a new future incompatible lint was added ambiguous_panic_imports see Tracking Issue for future-incompatibility lint ambiguous_panic_imports #147319. This allows current code to continue compiling, albeit with a new warning. Future editions of Rust make this an error and future versions of Rust can choose to make this error. Technically this is a breaking change, but crater gives us the confidence that the impact will be at worst a new warning for 99+% of public and private crates.

    • Code using #![no_implicit_prelude] and Rust edition 2015 will no longer automatically have access to the prelude macros. The following works on nightly by would stop working with this change:

      #![no_implicit_prelude]
      
      // Uncomment to fix error.
      // use std::{panic, vec};
      
      fn main() {
          let _ = vec![3, 6];
          panic!();
      }

    Crater found no instance of this pattern in use. Affected code can fix the issue by directly importing the macros. The new behavior matches the behavior of #![no_implicit_prelude] in Rust editions 2018 and beyond and it's intuitive meaning.

  • FCW: report_in_deps is currently set to true, but I have no strong opinion on that. I could see us reasonably starting with report_in_deps: false, I'll defer to the opinion of the lang team here. Regarding warn or deny by default, I strongly suggest warn by default as a start since by and large core::panic and std::panic behave the same and triggering the lint doesn't imply dangerous code. If we did deny by default the impact on the ecosystem would be much more severe, needlessly so in my opinion.

  • Other details: The unstable and never intended for public use format_args_nl macro is no longer publicly accessible.

  • Test coverage: The expected language and lint behavior is covered by a mix of existing and new UI tests.

@traviscross
Copy link
Contributor

  • I could see us reasonably starting with report_in_deps: false, I'll defer to the opinion of the lang team here... I strongly suggest warn by default as a start...

Speaking just for myself, but branch predicting based on our other recent decisions, I'd suggest going ahead and making this report_in_deps: false then. The principle here is that it probably doesn't make sense to prompt downstreams to file bugs against their upstreams until we're also willing to soft-break (with a deny-by-default lint) the build of the upstreams.

@traviscross
Copy link
Contributor

Looking at this diff, we're clearly going to need to dual FCP this with libs-api. @Voultapher, if you could please write up the details of what is changing on the library side to support this, that would be helpful.

@ehuss
Copy link
Contributor

ehuss commented Nov 9, 2025

Does this affect no_implicit_prelude in the 2015 edition?

@Voultapher
Copy link
Contributor Author

@traviscross wanting to avoid unclear responsibility I've focused the following to lib changes not already counted as language changes.

  • Reference: No lib changes needed. Already covered by lang.

  • Stabilized: No lib stabilizations.

  • Tool changes: No lib specific tool changes needed.

  • Breaking changes: The unstable and never intended for public use format_args_nl macro is no longer publicly accessible as requested by @petrochenkov. Affects <10 crates including dependencies.

  • Test coverage: The expected language and lint behavior is covered by a mix of existing and new UI tests.

  • Implementation details: The core and std macros are now exported via pub use in the prelude.

For reference here are the other two comments explaining this change:

@Voultapher
Copy link
Contributor Author

Does this affect no_implicit_prelude in the 2015 edition?

Indeed it does. I've amended the lang change comment. Note, we didn't find any public crates via crater affected by this change. Arguably it works closer to the intention of #[no_implicit_prelude] than before.

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

Labels

A-rustdoc-search Area: Rustdoc's search feature I-lang-radar Items that are on lang's radar and will need eventual work or consideration. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. perf-regression Performance regression. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team T-libs Relevant to the library team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Do not apply #[macro_use] to implicitly injected extern crate std;, use standard library prelude instead