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

@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
@Amanieu
Copy link
Member

Amanieu commented Sep 21, 2025

I had a quick look at the regressions. A lot of them are no_std crates which also explicitly import the std prelude in tests using this:

use std::prelude::v1::*;

This causes macros like panic to be ambiguous since it could refer either to core::panic in the prelude or the imported std::panic.

Example crate: https://github.com/Noratrieb/rustv32i/blob/main/rvdc/src/lib.rs#L1954
Crater report: https://crater-reports.s3.amazonaws.com/pr-139493/try%23ec62ac61f0f5e721f5059579f6a881ef2a3a6c75/gh/Noratrieb.rustv32i/log.txt

@Voultapher
Copy link
Contributor Author

Given that core::panic and std::panic don't have the exact same semantics, what's the ideal behavior is such a scenario?

Here is a minimal reproducer for the issue:

#![no_std]

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

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

The old behavior can be restored by adding use core::panic;. I'd argue that in the reproducer it's not exactly clear which panic is meant and maybe not directly intuitive that it still resolves to core::panic even after use std::prelude::v1::*;.

That said, breaking 10% of crates isn't great, even if it is only 95 root crates.

@traviscross
Copy link
Contributor

traviscross commented Sep 22, 2025

That said, breaking 10% of crates isn't great, even if it is only 95 root crates.

It might be worth going ahead and making the PRs to these 95 crates. Even if we don't break them (for now at least), they're relying on a resolution which is rather surprising, so they'd be better off in any world doing this explicitly.

That might later give us more options.

@Voultapher
Copy link
Contributor Author

Good point, I'll do that.

@Amanieu
Copy link
Member

Amanieu commented Sep 22, 2025

Note that std::panic is a strict superset of core::panic in that it supports more inputs (and even then, only on pre-2021 editions), so it's fine if we always resolve to std::panic here.

The main difference between them is that on older editions panic! accepted any type and would simply use that in a Box<dyn Any> as the panic payload. Today you need to do this using the panic_any function.

@traviscross
Copy link
Contributor

In broad strokes, this also seems related to:

In this case, the two panic macros aren't exactly the same item, but it seems conceptually that, at least in Rust 2021 and later, they perhaps could be.

@Amanieu
Copy link
Member

Amanieu commented Sep 22, 2025

I don't think this should be blocked on resolving #141043. This is an issue of name resolution priority: currently, prelude macros have a higher priority than glob-imported macros. We need to preserve this property for macros imported via glob imports marked with #[prelude_import].

Here's a different example:

[INFO] [stdout] error[E0659]: `dbg` is ambiguous
[INFO] [stdout]    --> src/java/class_file/parser.rs:259:5
[INFO] [stdout]     |
[INFO] [stdout] 259 |     dbg!(do_parse!(
[INFO] [stdout]     |     ^^^ ambiguous name
[INFO] [stdout]     |
[INFO] [stdout]     = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
[INFO] [stdout] note: `dbg` could refer to the macro imported here
[INFO] [stdout]    --> src/java/class_file/parser.rs:1:5
[INFO] [stdout]     |
[INFO] [stdout]   1 | use nom::*;
[INFO] [stdout]     |     ^^^^^^
[INFO] [stdout]     = help: consider adding an explicit import of `dbg` to disambiguate
[INFO] [stdout]     = help: or use `self::dbg` to refer to this macro unambiguously
[INFO] [stdout] note: `dbg` could also refer to a macro from prelude
[INFO] [stdout]    --> /rustc/ec62ac61f0f5e721f5059579f6a881ef2a3a6c75/library/std/src/prelude/mod.rs:123:13

nom::dbg imported via nom::* becomes ambiguous with the dbg from the prelude.

@Voultapher
Copy link
Contributor Author

Note that std::panic is a strict superset of core::panic in that it supports more inputs

While that's not 100% correct, given that Rust 2018 panic!(&String::new() is accepted by core::panic but not std::panic in practice and essence it's true.

Thinking a bit longer about the idea of sending patches to various projects that have the unintuitive core::panic resolution does not really seem worth it. A, it won't really help us here unless we plan to let this PR linger for years until enough of the ecosystem has upgraded to newer dependencies with the fix. B, while it might be a surprising resolution, it does not have surprising effects in practice, so it's harmless.

I agree with @Amanieu that we should fix this in the resolver.

@Amanieu
Copy link
Member

Amanieu commented Sep 23, 2025

Unfortunately I think this boils back down to the original issue that this PR has been trying to avoid, which is prioritization between glob imports and prelude macros.

@petrochenkov Any thoughts on how we might be able to fix this?

@traviscross traviscross added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. T-lang Relevant to the language team labels Sep 24, 2025
@petrochenkov
Copy link
Contributor

Any thoughts on how we might be able to fix this?

Not really.

Are there regressions not related to panics?
I suggest making an abridged version of this change that moves everything except panic from macro_use to stdlib prelude, and looking if something breaks in that case.

@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 Sep 25, 2025
@Amanieu
Copy link
Member

Amanieu commented Sep 25, 2025

Most of the failures are due to panic, but I've collected the ones that aren't:

If we can find a solution for the panic case then I think there are few enough regressions that we can get away with this change by fixing the affected crates.

@Amanieu
Copy link
Member

Amanieu commented Sep 25, 2025

However just not re-exporting panic won't work since this PR removes #[macro_use] on the implicit crate import from the prelude.

@petrochenkov
Copy link
Contributor

However just not re-exporting panic won't work since this PR removes #[macro_use] on the implicit crate import from the prelude.

It could use #[macro_use(panic)] instead of removing.
(Not sure whether it's needed on both std and core to avoid the regressions, or just one of them would be enough.)

@Voultapher
Copy link
Contributor Author

Voultapher commented Sep 25, 2025

Before bringing in #[macro_use] back in, could we please run a timing run. I don't think I have the rights to start one myself.

@Voultapher
Copy link
Contributor Author

Adding a warning about the unintuitive resolution might be good idea. It would move actively developed crates towards an explicit import, allowing for an eventual removal of the panic special casing and it would also help closed source projects not on crates.io, something we couldn't fix by upstreaming patches to the affected crates.

@Kobzol
Copy link
Member

Kobzol commented Sep 25, 2025

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Sep 25, 2025
…ros, r=<try>

Explicitly export core and std macros
@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Sep 25, 2025
@rust-bors
Copy link

rust-bors bot commented Sep 25, 2025

☀️ Try build successful (CI)
Build commit: f65cc8e (f65cc8e92b3e9d34b4cc0974ffc1db7476c6dee0, parent: 6f34f4ee074ce0affc7bbf4e2c835f66cd576f13)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (f65cc8e): comparison URL.

Overall result: ❌✅ regressions and improvements - BENCHMARK(S) FAILED

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please do so in sufficient writing along with @rustbot label: +perf-regression-triaged. If not, please fix the regressions and do another perf run. If its results are neutral or positive, the label will be automatically removed.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

❗ ❗ ❗ ❗ ❗
Warning ⚠️: The following benchmark(s) failed to build:

  • issue-46449
  • runtime:css

❗ ❗ ❗ ❗ ❗

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
0.6% [0.6%, 0.6%] 1
Regressions ❌
(secondary)
0.4% [0.2%, 0.6%] 4
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.1% [-0.1%, -0.1%] 2
All ❌✅ (primary) 0.6% [0.6%, 0.6%] 1

Max RSS (memory usage)

Results (primary 1.0%, secondary 0.6%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.9% [2.9%, 2.9%] 1
Regressions ❌
(secondary)
2.5% [1.1%, 5.1%] 11
Improvements ✅
(primary)
-0.8% [-0.8%, -0.8%] 1
Improvements ✅
(secondary)
-2.8% [-6.2%, -1.1%] 6
All ❌✅ (primary) 1.0% [-0.8%, 2.9%] 2

Cycles

Results (secondary -2.4%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-2.4% [-2.9%, -1.8%] 3
All ❌✅ (primary) - - 0

Binary size

Results (primary 0.0%, secondary 0.0%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.0% [0.0%, 0.0%] 8
Regressions ❌
(secondary)
0.0% [0.0%, 0.0%] 6
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.0% [0.0%, 0.0%] 8

Bootstrap: 471.619s -> 472.552s (0.20%)
Artifact size: 388.14 MiB -> 388.13 MiB (-0.00%)

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Sep 25, 2025
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. 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