Skip to content

Conversation

@Zalathar
Copy link
Member

@Zalathar Zalathar commented Nov 4, 2025

Successful merges:

r? @ghost
@rustbot modify labels: rollup

Create a similar rollup

Zalathar and others added 12 commits November 4, 2025 13:11
When working on the Rust parts of bootstrap, it's unhelpful for
`./x test bootstrap` to also run Python unit tests.
Also emit an error when `rustc_pass_indirectly_in_non_rustic_abis` is
used in combination with `repr(transparent)`.
…jorn3

Add `#[rustc_pass_indirectly_in_non_rustic_abis]`

This PR adds an internal `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute that can be applied to structs. Structs marked with this attribute will always be passed using `PassMode::Indirect { on_stack: false, .. }` when being passed by value to functions with non-Rustic calling conventions. This is needed by rust-lang#141980; see that PR for further details.

cc `@joshtriplett`
…r=davidtwco

FCW for repr(C) enums whose discriminant values do not fit into a c_int or c_uint

Context: rust-lang#124403

The current behavior of repr(C) enums is as follows:
- The discriminant values are interpreted as const expressions of type `isize`
- We compute the smallest size that can hold all discriminant values
- The target spec contains the smallest size for repr(C) enums
- We take the larger of these two sizes

Unfortunately, this doesn't always match what C compilers do. In particular, MSVC seems to *always* give enums a size of 4 bytes, whereas the algorithm above will give enums a size of up to 8 bytes on 64bit targets. Here's an example enum affected by this:
```
// We give this size 4 on 32bit targets (with a warning since the discriminant is wrapped to fit an isize)
// and size 8 on 64bit targets.
#[repr(C)]
enum OverflowingEnum {
    A = 9223372036854775807, // i64::MAX
}

// MSVC always gives this size 4 (without any warning).
// GCC always gives it size 8 (without any warning).
// Godbolt: https://godbolt.org/z/P49MaYvMd
enum overflowing_enum {
    OVERFLOWING_ENUM_A = 9223372036854775807,
};
```

If we look at the C standard, then up until C20, there was no official support enums without an explicit underlying type and with discriminants that do not fit an `int`. With C23, this has changed: now enums have to grow automatically if there is an integer type that can hold all their discriminants. MSVC does not implement this part of C23.

Furthermore, Rust fundamentally cannot implement this (without major changes)! Enum discriminants work fundamentally different in Rust and C:
- In Rust, every enum has a discriminant type entirely determined by its repr flags, and then the discriminant values must be const expressions of that type. For repr(C), that type is `isize`. So from the outset we interpret 9223372036854775807 as an isize literal and never give it a chance to be stored in a bigger type. If the discriminant is given as a literal without type annotation, it gets wrapped implicitly with a warning; otherwise the user has to write `as isize` explicitly and thus trigger the wrapping. Later, we can then decide to make the *tag* that stores the discriminant smaller than the discriminant type if all discriminant values fit into a smaller type, but those values have allready all been made to fit an `isize` so nothing bigger than `isize` could ever come out of this. That makes the behavior of 32bit GCC impossible for us to match.
-  In C, things flow the other way around: every discriminant value has a type determined entirely by its constant expression, and then the type for the enum is determined based on that. IOW, the expression can have *any type* a priori, different variants can even use a different type, and then the compiler is supposed to look at the resulting *values* (presumably as mathematical integers) and find a type that can hold them all. For the example above, 9223372036854775807 is a signed integer, so the compiler looks for the smallest signed type that can hold it, which is `long long`, and then uses that to compute the size of the enum (at least that's what C23 says should happen and GCC does this correctly).

Realistically I think the best we can do is to not attempt to support C23 enums, and to require repr(C) enums to satisfy the C20 requirements: all discriminants must fit into a c_int. So that's what this PR implements, by adding a FCW for enums with discriminants that do not fit into `c_int`. As a slight extension, we do *not* lint enums where all discriminants fit into a `c_uint` (i.e. `unsigned int`): while C20 does (in my reading) not allow this, and C23 does not prescribe the size of such an enum, this seems to behave consistently across compilers (giving the enum the size of an `unsigned int`). IOW, the lint fires whenever our layout algorithm would make the enum larger than an `int`, irrespective of whether we pick a signed or unsigned discriminant. This extension was added because [crater found](rust-lang#147017 (comment)) multiple cases of such enums across the ecosystem.

Note that it is impossible to trigger this FCW on targets where isize and c_int are the same size (i.e., the typical 32bit target): since we interpret discriminant values as isize, by the time we look at them, they have already been wrapped. However, we have an existing lint (overflowing_literals) that should notify people when this kind of wrapping occurs implicitly. Also, 64bit targets are much more common. On the other hand, even on 64bit targets it is possible to fall into the same trap by writing a literal that is so big that it does not fit into isize, gets wrapped (triggering overflowing_literals), and the wrapped value fits into c_int. Furthermore, overflowing_literals is just a lint, so if it occurs in a dependency you won't notice. (Arguably there is also a more general problem here: for literals of type `usize`/`isize`, it is fairly easy to write code that only triggers `overflowing_literals` on 32bit targets, and to never see that lint if one develops on a 64bit target.)

Specifically, the above example triggers the FCW on 64bit targets, but on 32bit targets we get this err-by-default lint instead (which will be hidden if it occurs in a dependency):
```
error: literal out of range for `isize`
  --> $DIR/repr-c-big-discriminant1.rs:16:9
   |
LL |     A = 9223372036854775807,
   |         ^^^^^^^^^^^^^^^^^^^
   |
   = note: the literal `9223372036854775807` does not fit into the type `isize` whose range is `-2147483648..=2147483647`
   = note: `#[deny(overflowing_literals)]` on by default
```
Also see the tests added by this PR.

This isn't perfect, but so far I don't think I have seen a better option. In rust-lang#146504 I tried adjusting our enum logic to make the size of the example enum above actually match what C compilers do, but that's a massive breaking change since we have to change the expected type of the discriminant expression from `isize` to `i64` or even `i128` -- so that seems like a no-go. To improve the lint we could analyze things on the HIR level and specifically catch "repr(C) enums with discriminants defined as literals that are too big", but that would have to be on top of the lint in this PR I think since we'd still want to also always check the actually evaluated value (which we can't always determined on the HIR level).

Cc `@workingjubilee` `@CAD97`
bootstrap: Split out a separate `./x test bootstrap-py` step

While testing changes to bootstrap, I was annoyed by the fact that `./x test bootstrap` spams a bunch of mysterious output to the console.

That output turns out to come from `bootstrap_test.py`, which runs unit tests for the Python parts of bootstrap. Those tests are (presumably) useful, but they don't add value when working on the Rust parts of bootstrap.

This PR therefore pulls them out into a separate test step that can be run with `./x test bootstrap-py`.
@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) 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. rollup A PR which is a rollup labels Nov 4, 2025
@Zalathar
Copy link
Member Author

Zalathar commented Nov 4, 2025

Rollup of everything.

@bors r+ rollup=never p=5

@bors
Copy link
Collaborator

bors commented Nov 4, 2025

📌 Commit 4f3816b has been approved by Zalathar

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 4, 2025
@bors
Copy link
Collaborator

bors commented Nov 4, 2025

⌛ Testing commit 4f3816b with merge e5efc33...

@bors
Copy link
Collaborator

bors commented Nov 4, 2025

☀️ Test successful - checks-actions
Approved by: Zalathar
Pushing e5efc33 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Nov 4, 2025
@bors bors merged commit e5efc33 into rust-lang:master Nov 4, 2025
12 checks passed
@rustbot rustbot added this to the 1.93.0 milestone Nov 4, 2025
@rust-timer
Copy link
Collaborator

📌 Perf builds for each rolled up PR:

PR# Message Perf Build Sha
#144529 Add #[rustc_pass_indirectly_in_non_rustic_abis] 94301f668761c7ffc84a240a44232fbe9cc04777 (link)
#147017 FCW for repr(C) enums whose discriminant values do not fit … d3ab2d71566b75c1db806f8765ef44cbae2f618c (link)
#148459 bootstrap: Split out a separate ./x test bootstrap-py step 1c93af1ce3d76f652c82aeddfc409d734baf561a (link)
#148468 add logging to fudge_inference_if_ok 59e97c2668d3b66e3d70b470d8347a72c99db0b0 (link)

previous master: 90b6588979

In the case of a perf regression, run the following command for each PR you suspect might be the cause: @rust-timer build $SHA

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

What is this? This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.

Comparing 90b6588 (parent) -> e5efc33 (this PR)

Test differences

Show 613 test diffs

Stage 1

  • [ui] tests/ui/abi/pass-indirectly-attr.rs: [missing] -> pass (J1)
  • [ui] tests/ui/attributes/pass-indirectly.rs: [missing] -> pass (J1)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant1.rs#ptr32: [missing] -> pass (J1)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant1.rs#ptr64: [missing] -> pass (J1)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant2.rs#ptr32: [missing] -> pass (J1)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant2.rs#ptr64: [missing] -> pass (J1)

Stage 2

  • [ui] tests/ui/abi/pass-indirectly-attr.rs: [missing] -> pass (J0)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant1.rs#ptr32: [missing] -> pass (J0)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant1.rs#ptr64: [missing] -> pass (J0)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant2.rs#ptr32: [missing] -> pass (J0)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant2.rs#ptr64: [missing] -> pass (J0)
  • [ui] tests/ui/abi/pass-indirectly-attr.rs: [missing] -> ignore (gcc backend is marked as ignore) (J2)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant1.rs#ptr32: [missing] -> ignore (gcc backend is marked as ignore) (J2)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant1.rs#ptr64: [missing] -> ignore (gcc backend is marked as ignore) (J2)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant2.rs#ptr32: [missing] -> ignore (gcc backend is marked as ignore) (J2)
  • [ui] tests/ui/enum-discriminant/repr-c-big-discriminant2.rs#ptr64: [missing] -> ignore (gcc backend is marked as ignore) (J2)
  • [ui] tests/ui/attributes/pass-indirectly.rs: [missing] -> pass (J3)

Additionally, 596 doctest diffs were found. These are ignored, as they are noisy.

Job group index

Test dashboard

Run

cargo run --manifest-path src/ci/citool/Cargo.toml -- \
    test-dashboard e5efc336720901420a8891dcdb67ca0a475dc03c --output-dir test-dashboard

And then open test-dashboard/index.html in your browser to see an overview of all executed tests.

Job duration changes

  1. dist-android: 1554.7s -> 2849.9s (+83.3%)
  2. dist-ohos-aarch64: 4325.6s -> 7164.1s (+65.6%)
  3. dist-various-2: 2185.0s -> 3522.5s (+61.2%)
  4. dist-x86_64-freebsd: 5092.7s -> 8093.1s (+58.9%)
  5. dist-aarch64-windows-gnullvm: 4926.4s -> 7706.8s (+56.4%)
  6. dist-x86_64-windows-gnullvm: 4808.7s -> 7446.4s (+54.9%)
  7. dist-ohos-armv7: 4243.3s -> 6478.8s (+52.7%)
  8. dist-ohos-x86_64: 4289.2s -> 6481.8s (+51.1%)
  9. dist-x86_64-illumos: 6240.8s -> 9379.2s (+50.3%)
  10. dist-apple-various: 4013.4s -> 5900.6s (+47.0%)
How to interpret the job duration changes?

Job durations can vary a lot, based on the actual runner instance
that executed the job, system noise, invalidated caches, etc. The table above is provided
mostly for t-infra members, for simpler debugging of potential CI slow-downs.

@Zalathar Zalathar deleted the rollup-zwlz09o branch November 4, 2025 22:22
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (e5efc33): comparison URL.

Overall result: ❌✅ regressions and improvements - please read the text below

Our benchmarks found a performance regression caused by this PR.
This might be an actual regression, but it can also be just noise.

Next Steps:

  • If the regression was expected or you think it can be justified,
    please write a comment with sufficient written justification, and add
    @rustbot label: +perf-regression-triaged to it, to mark the regression as triaged.
  • If you think that you know of a way to resolve the regression, try to create
    a new PR with a fix for the regression.
  • If you do not understand the regression or you think that it is just noise,
    you can ask the @rust-lang/wg-compiler-performance working group for help (members of this group
    were already notified of this PR).

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance

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
Regressions ❌
(secondary)
0.5% [0.1%, 0.9%] 8
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.6% [-0.6%, -0.5%] 3
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (primary 0.2%, secondary -0.9%)

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

mean range count
Regressions ❌
(primary)
2.7% [2.7%, 2.7%] 1
Regressions ❌
(secondary)
2.4% [0.8%, 4.0%] 2
Improvements ✅
(primary)
-2.3% [-2.3%, -2.3%] 1
Improvements ✅
(secondary)
-2.0% [-4.2%, -0.8%] 6
All ❌✅ (primary) 0.2% [-2.3%, 2.7%] 2

Cycles

Results (primary 4.7%, secondary -1.8%)

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

mean range count
Regressions ❌
(primary)
4.7% [4.7%, 4.7%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-1.8% [-1.8%, -1.8%] 1
All ❌✅ (primary) 4.7% [4.7%, 4.7%] 1

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 476.459s -> 473.413s (-0.64%)
Artifact size: 390.66 MiB -> 390.72 MiB (0.02%)

@rustbot rustbot added the perf-regression Performance regression. label Nov 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` A-testsuite Area: The testsuite used to check the correctness of rustc merged-by-bors This PR was explicitly merged by bors. perf-regression Performance regression. rollup A PR which is a rollup S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants