Skip to content

Distinguish repr(C) ZSTs from others in ABI computation - #156112

Open
Jules-Bertholet wants to merge 1 commit into
rust-lang:mainfrom
Jules-Bertholet:distinguish-c-zsts
Open

Jules-Bertholet wants to merge 1 commit into
rust-lang:mainfrom
Jules-Bertholet:distinguish-c-zsts

Conversation

@Jules-Bertholet

@Jules-Bertholet Jules-Bertholet commented May 3, 2026 •

Copy link
Copy Markdown
Contributor

View all comments

Implement #157973:

Some C ABIs pass and return ZSTs by pointer. But () should never be returned by pointer, as it must match void. To fix this, distinguish repr(C) ZSTs (and repr(transparent) wrappers around them) from other ZSTs in ABI computation.

Fixes rust-lang/unsafe-code-guidelines#552.

cc @RalfJung

@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 May 3, 2026
@rustbot

rustbot commented May 3, 2026

Copy link
Copy Markdown
Collaborator

r? @JohnTitor

rustbot has assigned @JohnTitor.
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

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 22 candidates

@rustbot rustbot added needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. T-lang Relevant to the language team labels May 3, 2026
@rust-log-analyzer

This comment has been minimized.

@RalfJung

RalfJung commented May 3, 2026

Copy link
Copy Markdown
Member

Fixes rust-lang/unsafe-code-guidelines#552;

I don't think this fixes that issue. We need #155299 for that (and a wording change to the ABI docs).


This new logic can be entirely removed again once we compute the right layout for zero-element repr(C) structs -- right? So it's more of a temporary work-around than something we "should" be doing?


Let's see if this new field shows up in perf.
@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label May 3, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request May 3, 2026
Distinguish `repr(C)` ZSTs from others in ABI computation
Comment thread tests/codegen-llvm/abi-win64-zst.rs Outdated
// CHECK: define win64cc void @pass_zst_win64(ptr {{[^,]*}})
// CHECK: define win64cc void @pass_rust_zst_win64()
#[no_mangle]
extern "win64" fn pass_rust_zst_win64(_: ()) {}

@RalfJung RalfJung May 3, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be interesting... I am not sure how to make sense of this ABI on non-MSVC targets. Given that the type layout itself is "wrong", how could one possibly actually call such a function...?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could call such a function from C with a signature of void pass_rust_zst_win64(). However, the Rust signature trips the improper_ctypes lint, so that's not something we are committing to.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, you could not. We don't allow any arguments to be omitted at the moment.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that I am talking about the "win64" ABI in general, not just this particular function -- I should have been more clear about that.

A "win64" function call on a windows-gnu or Linux target that involves a zero-field struct (or struct whose only field is a 0-element array) might just produce nonsense, right? We'd need repr(win64) as well.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading through prior discussion in rust-lang/unsafe-code-guidelines#552, I still agree with what I wrote there:

I think my stance here is what the win64 ABI simply does not support 1-ZST structs. We shouldn't take what gcc/clang do for that ABI as gospel since they do not "own" the ABI, MSVC/Microsoft does.

We should emit FFI warnings (and, eventually, errors) for code that uses an ABI outside of what the vendor has (explicitly or implicitly) defined. We should not take what GCC/clang do as gospel for Windows targets. For this concrete question that means we should disallow passing ZST.

And it seems like windows-gnu targets use the same ABI so this applies to them as well.

Is that too radical or is it something we could get away with?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this hasn't really been answered yet

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My position hasn't changed. We could always add a lint, but I don't think we should block this PR on that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the behavior of the win64 ABI with this PR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trivial ABI types are ignored, and empty repr(C) structs are passed by pointer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess for now that's the only thing we can do. However it'd be worth a FIXME to say that empty repr(C) structs shouldn't even exist on this target, i.e., this is primarily working around our layout computation being slightly off, and now is also needed due to backwards compatibility.

Comment thread compiler/rustc_abi/src/layout.rs Outdated
@Jules-Bertholet

Jules-Bertholet commented May 3, 2026 •

Copy link
Copy Markdown
Contributor Author

and a wording change to the ABI docs

That's part of this PR#157973.

This new logic can be entirely removed again once we compute the right layout for zero-element repr(C) structs -- right?

No, because these structs should remain zero-sized on many targets, including ones where they are passed by pointer.

@rustbot rustbot removed the T-libs Relevant to the library team, which will review and decide on the PR/issue. label May 3, 2026
@rust-bors

rust-bors Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 167ff94 (167ff940253840b897a826ca8996cc40ce7c71cd, parent: 54f67d248b14af80be8f3adc2094dd4a84ec2115)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (167ff94): comparison URL.

Overall result: ❌✅ regressions and improvements - please read:

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

Next, please: If you can, justify the regressions found in this try perf run in writing along with @rustbot label: +perf-regression-triaged. If not, fix the regressions and do another perf run. Neutral or positive results will clear the label automatically.

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

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.1% [0.0%, 0.1%] 4
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-0.1% [-0.6%, -0.0%] 5
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (primary -3.1%, 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)
3.9% [2.0%, 5.1%] 3
Improvements ✅
(primary)
-3.1% [-3.1%, -3.1%] 1
Improvements ✅
(secondary)
-2.4% [-2.4%, -2.4%] 1
All ❌✅ (primary) -3.1% [-3.1%, -3.1%] 1

Cycles

Results (secondary -0.2%)

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)
1.9% [0.6%, 5.5%] 7
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-2.6% [-4.1%, -0.6%] 6
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
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.0% [-0.0%, -0.0%] 4
Improvements ✅
(secondary)
-0.0% [-0.1%, -0.0%] 14
All ❌✅ (primary) -0.0% [-0.0%, -0.0%] 4

Bootstrap: 494.817s -> 493.602s (-0.25%)
Artifact size: 394.41 MiB -> 396.36 MiB (0.49%)

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels May 3, 2026
@RalfJung

RalfJung commented May 3, 2026 •

Copy link
Copy Markdown
Member

That's part of this PR.

If you are putting non-trivial implementation changes into the same PR as insta-stable docs updates (that will require t-lang FCP), you're making this PR a lot more difficult to work with. It'd be a good idea to split this up.

@rust-bors

This comment has been minimized.

@JohnTitor

Copy link
Copy Markdown
Member

r? RalfJung

@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 5, 2026
programskillforverification pushed a commit to programskillforverification/miri that referenced this pull request Oct 5, 2026
…alfJung

Distinguish `repr(C)` ZSTs from others in ABI compatibility rules

FCP: rust-lang/rust#157973 (comment)

(Split out from compiler implementation in rust-lang/rust#156112)

Some C ABIs pass and return ZSTs by pointer. But `()` should never be returned by pointer, as it must match `void`. To account for this, we have to weaken the present guarantee of "any two types with size 0 and alignment 1 are ABI-compatible" to exclude `repr(C)`.

[t-lang nomination summary comment](rust-lang/rust#157973 (comment))

Fixes rust-lang/unsafe-code-guidelines#552; see also rust-lang/rust#78586, rust-lang/rust#155299.
Also related to rust-lang/rust#155984.

@rustbot label T-lang A-ABI needs-fcp

@oli-obk oli-obk left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rust-bors

rust-bors Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 95811cf has been approved by oli-obk

It is now in the queue for this repository.

@rust-bors rust-bors Bot 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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 7, 2026
@JonathanBrouwer

Copy link
Copy Markdown
Member

@bors rollup=iffy
I think this was only rollup=never for perf right?
In that case, perf effect is small enough that this can be rolled up

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Oct 7, 2026
…, r=oli-obk

Distinguish `repr(C)` ZSTs from others in ABI computation

Implement rust-lang#157973:

Some C ABIs pass and return ZSTs by pointer. But `()` should never be returned by pointer, as it must match `void`. To fix this, distinguish `repr(C)`  ZSTs (and `repr(transparent)` wrappers around them) from other ZSTs in ABI computation.

Fixes rust-lang/unsafe-code-guidelines#552.

cc @RalfJung
@JonathanBrouwer

Copy link
Copy Markdown
Member

💔 I suspect this PR failed tests as part of a rollup
@bors r-

After fixing the problem, consider running a try job for the failed job before re-approving.

Link to failure: #163929 (comment)

@rust-bors rust-bors Bot 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-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Oct 7, 2026
@rust-bors

rust-bors Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

This PR was contained in a rollup (#163929), which was unapproved.

View changes since this unapproval

@rust-bors

This comment has been minimized.

@rustbot

rustbot commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Co-Authored-By: Ralf Jung <post@ralfj.de>
@Jules-Bertholet

Copy link
Copy Markdown
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 8, 2026
},
max_repr_align: None,
unadjusted_abi_align: Align(8 bytes),
repr_c: false,

@RalfJung RalfJung Oct 8, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So VaList<'_> is not repr_c? But it was before the most recent rebase? Odd.

View changes since the review

@Jules-Bertholet Jules-Bertholet Oct 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not from the rebase, that is to fix the test failure in rollup. It always should have been false (for Windows specifically)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, that seems surprising, we make ABI guarantees about that type after all...
It looks like it's a transparent wrapper around a pointer. That has guaranteed ABI but is not repr_c. I guess that matches the definition of the field. Makes me wonder if a general "has C-compatible ABI" field would make sense but that's a separate refactor.

@RalfJung

RalfJung commented Oct 8, 2026

Copy link
Copy Markdown
Member

@bors r=oli-obk

@rust-bors

rust-bors Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 916dda0 has been tentatively approved by oli-obk

It will be put into the queue for this repository once PR CI succeeds.

@rust-bors rust-bors Bot 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 Oct 8, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Oct 8, 2026
…, r=oli-obk

Distinguish `repr(C)` ZSTs from others in ABI computation

Implement rust-lang#157973:

Some C ABIs pass and return ZSTs by pointer. But `()` should never be returned by pointer, as it must match `void`. To fix this, distinguish `repr(C)`  ZSTs (and `repr(transparent)` wrappers around them) from other ZSTs in ABI computation.

Fixes rust-lang/unsafe-code-guidelines#552.

cc @RalfJung
rust-bors Bot pushed a commit that referenced this pull request Oct 8, 2026
…uwer

Rollup of 19 pull requests

Successful merges:

 - #156112 (Distinguish `repr(C)` ZSTs from others in ABI computation)
 - #157941 (Deny partial `-Z stack-protector` by default in all editions)
 - #163462 (Fix COFF renaming of decorated (stdcall/fastcall/vectorcall) exports)
 - #163855 (Include enclosing item's context on const errors)
 - #163861 (Run LLDB debuginfo tests on `x86_64-mingw`)
 - #163913 ( Silence redundant failed obligations on the same statement)
 - #161201 (Speed up tidy again)
 - #163380 (Tweak "name not found" resolution error when it happens from within a derive expansion)
 - #163538 (Add `rustc::missing_generic_type_visitable` lint)
 - #163617 (mips: make `Complex<T>` ABI match GCC)
 - #163772 (comptime fn error: suggest wrapping in const block)
 - #163813 (use pre-borrowck typing env for early MIR validation)
 - #163924 (replace instances of NonNull::new(&mut x).expect("...") with NonNull::from_mut)
 - #163958 (only make `RustaceansAreAwesome` satisfy trait clauses)
 - #163960 (vexos: clear .bss from assembly)
 - #163974 (Condense AdtDef lang item checks into one match)
 - #163979 (Add `bf16` to arm features)
 - #163989 (Revert "compiletest: stream output of executor process when --no-capture is set")
 - #163995 (m68k-unknown-none-elf: Remove code model)

Failed merges:

 - #163832 (reject non-async coroutine closures as async callables)
 - #163972 (const-eval: ICE when we hit a non-const fn)

This branch has not been deployed

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

Labels

perf-regression Performance regression. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Any two types with size 0 and alignment 1 are ABI-compatible" vs the Windows ABI

8 participants