Repository navigation
Distinguish repr(C) ZSTs from others in ABI compatibility rules - #157973
Conversation
|
rustbot has assigned @Mark-Simulacrum. Use Why was this reviewer chosen?The reviewer was selected based on:
|
| /// - Alignment 1 | ||
| /// - Not `repr(C)` | ||
| /// - Not a `repr(transparent)` wrapper around a type that fails to satisfy these conditions | ||
| /// - Not an array whose element type fails to satisfy these conditions |
There was a problem hiding this comment.
We exempt arrays for 2 reasons:
- A future version of C, or some other language we would like to do FFI with, might allow passing arrays to functions directly by value, in a way that would conflict with these guarantees
- It would be nice to also use "trivial ABI" in the specification of
repr(C), and we need this clause for that. See discussion at repr(ordered_fields) rfcs#3845 (comment)
We could also simplify this clause by saying merely:
| /// - Not an array whose element type fails to satisfy these conditions | |
| /// - Not an array |
The downside would be a larger breaking change.
Note that repr(transparent) will need to be adjusted to account for this change (by rejecting non-trivial arrays as "additional" fields).
There was a problem hiding this comment.
I'm fine with saying that "all arrays with trivial-ABI element type have trivial ABI".
However, even that less-breaking version breaks ghost again, right? Similar to dtolnay/ghost#41. ghost uses a zero-length array of *const T, which definitely does not have trivial ABI. I don't know why they do that...
EDIT: Ah, ghost is saved by having a repr(Rust) type around the array, under the rules discussed here.
There was a problem hiding this comment.
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).
I think the implication here is that () is repr(C)? Am I reading that right? Where do we make that guarantee? Or is the thinking that the language here would make () and #[repr(C)] struct Foo; not ABI compatible?
One callout is that ZSTs aren't (I think?) standardized -- C and C++ without extensions both require types to be non-ZST if I remember right (e.g., see https://stackoverflow.com/a/2632075). Maybe that has changed since then though?
It seems like at minimum, it would be nice to avoid weakening this guarantee for Rust ABI even if we do so for C ABIs as a result of the weird platforms.
There was a problem hiding this comment.
Or is the thinking that the language here would make
()and#[repr(C)] struct Foo;not ABI compatible?
Yes, this.
One callout is that ZSTs aren't (I think?) standardized
Correct.
|
@rust-lang/opsem @rust-lang/lang what do you think? I think we do have to take back a bit of what we promised here, since we did promise too much. The current docs say:
This is plain wrong for // This is returned by-ptr.
#[repr(C)]
struct T1 {}
// This matches a C function returning `void`.
type T2 = ();
So the proposal is to restrict the above rule as follows:
Under the old rules, we effectively said "All 1-ZST have trivial ABI". Now we have some further restrictions. I think the only types that used to have trivial ABI but don't any more are Note that we also have to adjust the logic for
I cratered the 2nd part and found 0 regressions. I don't know how to measure the fallout from the 1st breakage. We should implement this in Miri, but even that will just give us a very incomplete partial picture. That said, given that the current docs are wrong, we have to do something. The only actually open question (in my eyes) is how bespoke we want the rules to be with the aim of breaking less code.
|
|
We talked about this briefly in the lang call last week. We had wanted to see more discussion, if possible, particularly from those on opsem, to inform the decision. Looking at it now, it occurs to me that this would also benefit from a Reference PR, and that such a PR would help facilitate the lang discussion. |
|
Does the Reference have any discussion of ABI compatibility currently? Hard to make a PR with a diff to something that's not even in the Reference yet. |
I had in mind defining trivial ABI and documenting this new rule in the Reference. Where the Reference doesn't fully cover something, we've in the past then not added new or changed language rules in that area to the Reference (because we don't expect people to fully document an area in order to document one change). I now think that's less good than simply accepting (and documenting) that the Reference is incomplete in that area and still adding the rule for the thing we're changing in the language. So that's what we've been asking for on other changes: documenting the one rule being added. But, here, I'll take care of it. I'm working on adding all of the ABI rules to the Reference. I'll roll this up in that. |
|
Note that once this merges, I'll propose a follow-up to change what we accept in |
4a0ec97 to
103bac2
Compare
Co-Authored-By: Brian Smith <brian@briansmith.org> Co-Authored-By: Ralf Jung <post@ralfj.de>
103bac2 to
fa05b78
Compare
|
Finally -- thanks @Jules-Bertholet and everyone else who was involved. :) |
…uwer Rollup of 9 pull requests Successful merges: - #163655 (explicitly handle tests that pass with -Znext-solver) - #159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc) - #163572 (Update the minimum external LLVM to 22) - #129822 (Docs - type guarantees update) - #157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules) - #162332 (preserve overflow in builtin Field candidates) - #163574 (intrinsics: Rename `abort` to `abort_immediate`) - #163638 (avoid trivial `fn map_bound` validations) - #163660 (yeet compare-mode-coherence)
…uwer Rollup of 9 pull requests Successful merges: - #163655 (explicitly handle tests that pass with -Znext-solver) - #159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc) - #163572 (Update the minimum external LLVM to 22) - #129822 (Docs - type guarantees update) - #157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules) - #162332 (preserve overflow in builtin Field candidates) - #163574 (intrinsics: Rename `abort` to `abort_immediate`) - #163638 (avoid trivial `fn map_bound` validations) - #163660 (yeet compare-mode-coherence)
Rollup merge of #157973 - Jules-Bertholet:distinguish-c-zst-docs, r=RalfJung Distinguish `repr(C)` ZSTs from others in ABI compatibility rules FCP: #157973 (comment) (Split out from compiler implementation in #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](#157973 (comment)) Fixes rust-lang/unsafe-code-guidelines#552; see also #78586, #155299. Also related to #155984. @rustbot label T-lang A-ABI needs-fcp
…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
…uwer Rollup of 9 pull requests Successful merges: - rust-lang/rust#163655 (explicitly handle tests that pass with -Znext-solver) - rust-lang/rust#159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc) - rust-lang/rust#163572 (Update the minimum external LLVM to 22) - rust-lang/rust#129822 (Docs - type guarantees update) - rust-lang/rust#157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules) - rust-lang/rust#162332 (preserve overflow in builtin Field candidates) - rust-lang/rust#163574 (intrinsics: Rename `abort` to `abort_immediate`) - rust-lang/rust#163638 (avoid trivial `fn map_bound` validations) - rust-lang/rust#163660 (yeet compare-mode-coherence)
…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
…uwer Rollup of 9 pull requests Successful merges: - rust-lang/rust#163655 (explicitly handle tests that pass with -Znext-solver) - rust-lang/rust#159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc) - rust-lang/rust#163572 (Update the minimum external LLVM to 22) - rust-lang/rust#129822 (Docs - type guarantees update) - rust-lang/rust#157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules) - rust-lang/rust#162332 (preserve overflow in builtin Field candidates) - rust-lang/rust#163574 (intrinsics: Rename `abort` to `abort_immediate`) - rust-lang/rust#163638 (avoid trivial `fn map_bound` validations) - rust-lang/rust#163660 (yeet compare-mode-coherence)
…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
…uwer Rollup of 9 pull requests Successful merges: - rust-lang/rust#163655 (explicitly handle tests that pass with -Znext-solver) - rust-lang/rust#159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc) - rust-lang/rust#163572 (Update the minimum external LLVM to 22) - rust-lang/rust#129822 (Docs - type guarantees update) - rust-lang/rust#157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules) - rust-lang/rust#162332 (preserve overflow in builtin Field candidates) - rust-lang/rust#163574 (intrinsics: Rename `abort` to `abort_immediate`) - rust-lang/rust#163638 (avoid trivial `fn map_bound` validations) - rust-lang/rust#163660 (yeet compare-mode-coherence)
…uwer Rollup of 9 pull requests Successful merges: - rust-lang/rust#163655 (explicitly handle tests that pass with -Znext-solver) - rust-lang/rust#159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc) - rust-lang/rust#163572 (Update the minimum external LLVM to 22) - rust-lang/rust#129822 (Docs - type guarantees update) - rust-lang/rust#157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules) - rust-lang/rust#162332 (preserve overflow in builtin Field candidates) - rust-lang/rust#163574 (intrinsics: Rename `abort` to `abort_immediate`) - rust-lang/rust#163638 (avoid trivial `fn map_bound` validations) - rust-lang/rust#163660 (yeet compare-mode-coherence)
…, 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
…uwer Rollup of 9 pull requests Successful merges: - rust-lang/rust#163655 (explicitly handle tests that pass with -Znext-solver) - rust-lang/rust#159924 (Send -fno-lto when linker plugin LTO is not requested to avoid having GCC do LTO when using rustc_codegen_gcc) - rust-lang/rust#163572 (Update the minimum external LLVM to 22) - rust-lang/rust#129822 (Docs - type guarantees update) - rust-lang/rust#157973 (Distinguish `repr(C)` ZSTs from others in ABI compatibility rules) - rust-lang/rust#162332 (preserve overflow in builtin Field candidates) - rust-lang/rust#163574 (intrinsics: Rename `abort` to `abort_immediate`) - rust-lang/rust#163638 (avoid trivial `fn map_bound` validations) - rust-lang/rust#163660 (yeet compare-mode-coherence)
…, 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
Rollup merge of #156112 - Jules-Bertholet:distinguish-c-zsts, r=oli-obk Distinguish `repr(C)` ZSTs from others in ABI computation 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
View all comments
FCP: #157973 (comment)
(Split out from compiler implementation in #156112)
Some C ABIs pass and return ZSTs by pointer. But
()should never be returned by pointer, as it must matchvoid. 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 excluderepr(C).t-lang nomination summary comment
Fixes rust-lang/unsafe-code-guidelines#552; see also #78586, #155299.
Also related to #155984.
@rustbot label T-lang A-ABI needs-fcp