compiler: Forward attributes to eii-expanded macros
Since https://github.com/rust-lang/rust/pull/150592 is quite complicated to reason about I figured it would be good to split it up in smaller pieces that are easier to digest. Here is the attribute fix in isolation.
## The Problem
With this eii in **library/std/src/io/mod.rs**:
```rs
/// Foo
#[eii(on_broken_pipe)]
#[unstable(feature = "on_broken_pipe", issue = "150588")]
pub fn on_broken_pipe() -> OnBrokenPipe {
OnBrokenPipe::BackwardsCompatible
}
```
you currently get this compilation error:
```
error: attribute macro has missing stability attribute
--> library/std/src/io/mod.rs:2269:1
|
2269 | #[eii(on_broken_pipe)]
| ^^^^^^^^^^^^^^^^^^^^--
| |
| in this attribute macro expansion
|
::: library/core/src/macros/mod.rs:1899:5
|
1899 | pub macro eii($item:item) {
| ------------- in this expansion of `#[eii]`
```
because with ` MAGIC_EXTRA_RUSTFLAGS=-Zunpretty=expanded ./x build library/std` we can see that a pub item in the expanded code is indeed missing that attribute:
```rs
const _: () =
{
#[on_broken_pipe]
fn on_broken_pipe() -> OnBrokenPipe {
OnBrokenPipe::BackwardsCompatible
}
};
unsafe extern "Rust" {
/// Foo
#[unstable(feature = "on_broken_pipe", issue = "150588")]
#[rustc_eii_extern_item]
pub safe fn on_broken_pipe()
-> OnBrokenPipe;
}
#[rustc_builtin_macro(eii_shared_macro)]
#[eii_extern_target(on_broken_pipe)]
pub macro on_broken_pipe { () => {} }
```
## The Solution
With the fix, that error goes away because we get this expanded code instead:
```rs
const _: () =
{
#[on_broken_pipe]
fn on_broken_pipe() -> OnBrokenPipe {
OnBrokenPipe::BackwardsCompatible
}
};
unsafe extern "Rust" {
/// Foo
#[unstable(feature = "on_broken_pipe", issue = "150588")]
#[rustc_eii_extern_item]
pub safe fn on_broken_pipe()
-> OnBrokenPipe;
}
/// Foo
#[unstable(feature = "on_broken_pipe", issue = "150588")]
#[rustc_builtin_macro(eii_shared_macro)]
#[eii_extern_target(on_broken_pipe)]
pub macro on_broken_pipe { () => {} }
```
Note that we also need to forward the docs, otherwise get get (fatal) warnings like these:
```
warning: missing documentation for an attribute macro
--> library/std/src/io/mod.rs:2269:1
```
r? @jdonszelmann
Tracking issues:
- https://github.com/rust-lang/rust/issues/125418
- https://github.com/rust-lang/rust/issues/150588
### What about a test?
https://github.com/rust-lang/rust/pull/150591 will prevent regressions once it lands since it does not build without this fix. I think it is overkill to add a temporary eii to std before that.
Remove std_detect_file_io and std_detect_dlsym_getauxval features
They were introduced back when std_detect was a standalone crate published to crates.io. The [motivation](https://github.com/rust-lang/stdarch/issues/655) for `std_detect_dlsym_getauxval` was to allow using `getauxval` without `dlopen` when statically linking musl, which we now unconditionally do for musl. And for `std_detect_file_io` to allow `no_std` usage, which std_detect now supports even with that feature enabled as it directly uses libc. This also prevents accidentally disabling runtime feature detection when using `cargo build -Zbuild-std -Zbuild-std-features=`
Fix ICE: can't type-check body of DefId for issue #148729
This commit fixes https://github.com/rust-lang/rust/issues/148729 for min_const_generic_args https://github.com/rust-lang/rust/issues/132980.
It's pretty small PR. The first commit makes sure that the `type_const`s are made into normal consts in const expressions.
The next one just handles the case https://github.com/rust-lang/rust/issues/148729 of where the type of the const was omitted at which point it was trying to treat a `type_const` again as a regular const. That obviously will fail since a type_const does not have a body.
@rustbot label +F-associated_const_equality +F-min_generic_const_args +I-ICE
THIR patterns: Replace `AscribeUserType` and `ExpandedConstant` wrappers with per-node data
This PR removes the `AscribeUserType` and `ExpandedConstant` variants from `thir::PatKind`, and replaces them with an `Option<Box<PatExtra>>` field attached to every `thir::Pat`.
### Why remove these variants?
Unlike other THIR pattern kinds, these variants are mere “wrappers” that exist to attach some additional information to an underlying pattern node.
There are several places where code that consumes THIR patterns needs to carefully “unpeel” any wrapper nodes, in order to match on the underlying pattern. This is clunky, and easy to forget to do, especially since it's not always obvious where the wrapper nodes can and can't appear.
Attaching the data to an optional per-node field makes it easier for consuming code to simply ignore the extra data when it is not relevant.
(One downside is that it is now easier to accidentally ignore the extra data when it *is* relevant, but I think that's generally a favourable tradeoff.)
### Impact
After this change, THIR pattern trees should be “logically identical” to the previous THIR pattern trees, in the sense that information that was carried by wrapper nodes should now be directly attached to the non-wrapper nodes that were being wrapped. Types and spans associated with THIR pattern nodes should (hopefully!) still be accurate.
There should be no change to the output of THIR-based checks or MIR building.
Fix dso_local for external statics with linkage
Tracking issue of the feature: rust-lang/rust#127488
DSO local attributes are not correctly applied to extern statics with `#[linkage = "foo"]` as we generate an internal global for such statics, and the we evaluate (and apply) DSO attributes on the internal one instead.
Fix this by applying DSO local attributes on the actually extern ones, too.
Implement create_dir_all() to operate iteratively instead of recursively
The current implementation of `create_dir_all(...)` in std::fs operates recursively. As mentioned in rust-lang/rust#124309, this could run into a stack overflow with big paths. To avoid this stack overflow issue, this PR implements the method in an iterative manner, preserving the documented behavior of:
```
Recursively create a directory and all of its parent components if they are missing.
This function is not atomic. If it returns an error, any parent components it was able to create will remain.
If the empty path is passed to this function, it always succeeds without creating any directories.
```
Rollup of 11 pull requests
Successful merges:
- rust-lang/rust#150269 (Remove inactive nvptx maintainer)
- rust-lang/rust#150713 (mgca: Type-check fields of struct expr const args)
- rust-lang/rust#150765 (rustc_parse_format: improve error for missing `:` before `?` in format args)
- rust-lang/rust#150847 (Fix broken documentation links to SipHash)
- rust-lang/rust#150867 (rustdoc_json: Remove one call to `std::mem::take` in `after_krate`)
- rust-lang/rust#150872 (Fix some loop block coercion diagnostics)
- rust-lang/rust#150874 (Ignore `rustc-src-gpl` in fast try builds)
- rust-lang/rust#150875 (Refactor artifact keep mode in bootstrap)
- rust-lang/rust#150876 (Mention that `rustc_codegen_gcc` is a subtree in `rustc-dev-guide`)
- rust-lang/rust#150882 (Supress unused_parens lint for guard patterns)
- rust-lang/rust#150884 (Update bors email in CI postprocessing step)
Failed merges:
- rust-lang/rust#150869 (Emit error instead of delayed bug when meeting mismatch type for const tuple)
r? @ghost
Reflection MVP
I am opening this PR for discussion about the general design we should start out with, as there are various options (that are not too hard to transition between each other, so we should totally just pick one and go with it and reiterate later)
r? @scottmcm and @joshtriplett
project goal issue: https://github.com/rust-lang/rust-project-goals/issues/406
tracking issue: https://github.com/rust-lang/rust/issues/146922
The design currently implemented by this PR is
* `TypeId::info` (method, usually used as `id.info()` returns a `Type` struct
* the `Type` struct has fields that contain information about the type
* the most notable field is `kind`, which is a non-exhaustive enum over all possible type kinds and their specific information. So it has a `Tuple(Tuple)` variant, where the only field is a `Tuple` struct type that contains more information (The list of type ids that make up the tuple).
* To get nested type information (like the type of fields) you need to call `TypeId::info` again.
* There is only one language intrinsic to go from `TypeId` to `Type`, and it does all the work
An alternative design could be
* Lots of small methods (each backed by an intrinsic) on `TypeId` that return all the individual information pieces (size, align, number of fields, number of variants, ...)
* This is how C++ does it (see https://lemire.me/blog/2025/06/22/c26-will-include-compile-time-reflection-why-should-you-care/ and https://isocpp.org/files/papers/P2996R13.html#member-queries)
* Advantage: you only get the information you ask for, so it's probably cheaper if you get just one piece of information for lots of types (e.g. reimplementing size_of in terms of `TypeId::info` is likely expensive and wasteful)
* Disadvantage: lots of method calling (and `Option` return types, or "general" methods like `num_fields` returning 0 for primitives) instead of matching and field accesses
* a crates.io crate could implement `TypeId::info` in terms of this design
The backing implementation is modular enough that switching from one to the other is probably not an issue, and the alternative design could be easier for the CTFE engine's implementation, just not as nice to use for end users (without crates wrapping the logic)
One wart of this design that I'm fixing in separate branches is that `TypeId::info` will panic if used at runtime, while it should be uncallable
Otherwise you get errors like these if you have an Externally
Implementable Item defined in std:
error: attribute macro has missing stability attribute
--> library/std/src/io/mod.rs:2269:1
|
2269 | #[eii(on_broken_pipe)]
| ^^^^^^^^^^^^^^^^^^^^--
| |
| in this attribute macro expansion
|
::: library/core/src/macros/mod.rs:1899:5
|
1899 | pub macro eii($item:item) {
| ------------- in this expansion of `#[eii]`
Or (fatal) warnings like these:
warning: missing documentation for an attribute macro
--> library/std/src/io/mod.rs:2269:1
Refactor artifact keep mode in bootstrap
This makes it easier to understand which artifacts will be stored in the build stamp. Should help with https://github.com/rust-lang/rust/pull/145343.
Before, there were two booleans (keep .rmeta files and a special mode for rustc). I created an explicit enum for it instead. The mapping is:
- `(false, false)` => `ArtifactKeepMode::OnlyRlib`
- `(true, false)` => `ArtifactKeepMode::OnlyRmeta` (used for check/clippy builds)
- `(false, true)` => special rustc mode
r? @bjorn3
rustdoc_json: Remove one call to `std::mem::take` in `after_krate`
This patch removes one call to `std::mem::take` to save two `memcpy`s: `JsonRenderer::index` can be quite large as noted https://github.com/rust-lang/rust/pull/142335. `self.index` can be passed directly to `types::Crate`. This removal makes `self` immutable.
The private `serialize_and_write` method is moved as a function: the `self` argument is replaced by `sess: &Session`. This `&Session` was fetched earlier in `after_krate` in all cases. This change allows to call `serialize_and_write` after `output_crate` is created, without having a conflict around the move of `self`: the borrow checker is now happy.
I wasn't able to measure the performance impact though because I don't know how to modify `rustc-perf` as [@nnethercote did](https://github.com/rust-lang/rust/pull/142335#issuecomment-2961252113) (sorry).
---
Follow up of https://github.com/rust-lang/rust/pull/142335.
r? @nnethercote
Fix broken documentation links to SipHash
The documentation of `SipHasher` previously linked to a page about SipHash on https://131002.net, a domain registered to Jean-Philippe Aumasson, one of the co-authors of the original SipHash paper (alongside Daniel J Bernstein).
That domain now redirects to another of Mr Aumasson's domains, https://www.aumasson.jp, but which does not host a similar page dedicated to SipHash. Instead, his site links to a GitHub repository containing a C implementation together with links to the original research paper. Mr Bernstein's own site, https://cr.yp.to, only hosts a copy of the research paper.
Therefore the GitHub repository appears to be the most official and complete reference to which we can link.
Fixesrust-lang/rust#150806
r? reddevilmidzy
rustc_parse_format: improve error for missing `:` before `?` in format args
Detect the `{ident?}` pattern where `?` is immediately followed by `}` and emit a clearer diagnostic explaining that `:` is required for Debug formatting. This avoids falling back to a generic “invalid format string” error and adds a targeted UI test for the case.
Remove inactive nvptx maintainer
Since I just saw the discussion in [#t-compiler > Starting to enforce Tier 2-to-3 downgrade](https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/Starting.20to.20enforce.20Tier.202-to-3.20downgrade/with/564788312), and I saw him pinged on PRs or issues. His last active open-source contributions were in early 2022: https://github.com/RDambrosio016 and IIRC he also mentioned that he had moved on.
ping @RDambrosio016 so you can confirm or correct me, if you want to chime in. I also pinged him on Zulip.
cc @kjetilkjeka who is the other maintainer and active on related issues/prs for his target.
I'd leave it open for a while, but
r? @jieyouxu
resolve: Factor out and document the glob binding overwriting logic
Also, avoid creating fresh name declarations and overwriting declarations in modules to update some fields in `DeclData`, when possible.
Instead, change the fields directly in `DeclData` using cells.
Unblocks https://github.com/rust-lang/rust/pull/149195.
67ea84d erroneously added this special-case when introducing `DesugaringKind::WhileLoop`.
It had the unintended effect of emitting erroneous diagnostics in certain `while` blocks.
Handling for inherent associated consts is missing elsewhere, remove so it can be handled later in that handling.
Diagnostic not always be emitted on associated constant
Add a test case and Fix for a different ICE I encountered.
I noticed when trying various permuations of the test case code to see if I could find anymore ICEs. I did, but not one that I expected. So in the instances of the a named const not having any args, insantiate it directly. Since it is likely an inherent assocaiated const.
Added tests.
Centralize the is_type_const() logic.
I also noticed basically the exact same check in other part the code.
Const blocks can't be a type_const, therefore this check is uneeded.
Fix comment spelling error.
get_all_attrs is not valid to call for all DefIds it seems.
Make sure that if the type is omitted for a type_const that we don't ICE.
Co-Authored-By: Boxy <rust@boxyuwu.dev>
Don't check `[mentions]` paths in submodules from tidy
As we were reminded in [#triagebot > Mentions glob matching](https://rust-lang.zulipchat.com/#narrow/channel/224082-triagebot/topic/Mentions.20glob.20matching/with/567093226), triagebot cannot see changes in submodules.
So let's reflect that in the `tidy` check to avoid accidentally adding paths inside submodules.
I tested it with these entries:
```toml
[mentions."src/tools/cargo"]
cc = ["@ehuss"]
[mentions."src/tools/cargo/"]
cc = ["@ehuss"]
[mentions."src/tools/cargo/*"]
cc = ["@ehuss"]
[mentions."src/tools/cargo/README.md"]
cc = ["@ehuss"]
```
and got (as expected):
```
tidy [triagebot]: triagebot.toml [mentions.*] 'src/tools/cargo/README.md' cannot match inside a submodule
tidy [triagebot]: triagebot.toml [mentions.*] contains 'src/tools/cargo/*' which doesn't match any file or directory in the repository
```
Fix std::fs::copy on WASI by setting proper OpenOptions flags
When PR rust-lang/rust#147572 switched WASI to use Unix-style filesystem APIs, the open_to_and_set_permissions function for WASI was implemented to call OpenOptions::new().open() without setting any access mode flags.
This causes std::fs::copy to fail with the error:
"must specify at least one of read, write, or append access"
The fix is to explicitly set .write(true), .create(true), and .truncate(true) on the OpenOptions, matching the behavior of the non-WASI Unix implementation but without the permission handling that WASI doesn't support.
Minimal reproduction:
```rs
fn main() {
std::fs::write("/src.txt", b"test").unwrap();
match std::fs::copy("/src.txt", "/dst.txt") {
Ok(_) => println!("PASS: fs::copy works!"),
Err(e) => println!("FAIL: {}", e),
}
}
```
# Compile and run:
rustc +nightly --target wasm32-wasip2 test.rs -o test.wasm
wasmtime -S cli --dir . test.wasm
# Before fix: FAIL: must specify at least one of read, write, or append access
# After fix: PASS: fs::copy works!
Note: The existing test library/std/src/fs/tests.rs::copy_file_ok would have caught this regression if the std test suite ran on WASI targets. Currently std tests don't compile for wasm32-wasip2 due to Unix-specific test code in library/std/src/sys/fd/unix/tests.rs.
Fixes the regression introduced in nightly-2025-12-10.
r? @alexcrichton
Fix for ICE: eii: fn / macro rules None in find_attr()
Closesrust-lang/rust#149981
This used to ICE:
```rust
macro_rules! foo_impl {}
#[eii]
fn foo_impl() {}
```
`#[eii]` generates a macro (called `foo_impl`) and a default impl. So the partial expansion used to roughly look like the following:
```rust
macro_rules! foo_impl {} // actually resolves here
extern "Rust" {
fn foo_impl();
}
#[eii_extern_target(foo_impl)]
macro foo_impl {
() => {};
}
const _: () = {
#[implements_eii(foo_impl)] // assumed to name resolve to the macro v2 above
fn foo_impl() {}
};
```
Now, shadowing rules for macrov2 and macrov1 are super weird! Take a look at this: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=23f21421921360478b0ec0276711ad36
So instead of resolving to the macrov2, we resolve the macrov1 named the same thing.
A regression test was added to this, and some span_delayed_bugs were added to make sure we catch this in the right places. But that didn't fix the root cause.
To make sure this simply cannot happen again, I made it so that we don't even need to do a name resolution for the default. In other words, the new partial expansion looks more like:
```rust
macro_rules! foo_impl {}
extern "Rust" {
fn foo_impl(); // resolves to here now!!!
}
#[eii_extern_target(foo_impl)]
macro foo_impl {
() => {};
}
const _: () = {
#[implements_eii(known_extern_target=foo_impl)] // still name resolved, but directly to the foreign function.
fn foo_impl() {}
};
```
The reason this helps is that name resolution for non-macros is much more predictable. It's not possible to have two functions like that with the same name in scope.
We used to key externally implementable items off of the defid of the macro, but now the unique identifier is the foreign function's defid which seems much more sane.
Finally, I lied a tiny bit because the above partial expansion doesn't actually work.
```rust
extern "Rust" {
fn foo_impl(); // not to here
}
const _: () = {
#[implements_eii(known_extern_target=foo_impl)] // actually resolves to this function itself
fn foo_impl() {} // <--- so to here
};
```
So the last few commits change the expansion to actually be this:
```rust
macro_rules! foo_impl {}
extern "Rust" {
fn foo_impl(); // resolves to here now!!!
}
#[eii_extern_target(foo_impl)]
macro foo_impl {
() => {};
}
const _: () = {
mod dflt { // necessary, otherwise `super` doesn't work
use super::*;
#[implements_eii(known_extern_target=super::foo_impl)] // now resolves to outside the `dflt` module, so the foreign item.
fn foo_impl() {}
}
};
```
I apologize to whoever needs to review this, this is very subtle and I hope this makes it clear enough 😭.
Fix ICE in inline always warning emission.
The calls to `def_path_str` were outside the decorate callback in `node_span_lint` which caused an ICE when the warning was an allowed warning due to the call to `def_path_str` being executed but the warning not actually being emitted.
r? @davidtwco