Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spec abi chapter #1545

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open

Conversation

chorman0773
Copy link
Contributor

This rewrites the abi chapter, and adds call compatibility to the chapter.

@chorman0773 chorman0773 added A-abi Area: ABI S-waiting-on-review Status: The marked PR is awaiting review from the PR author. T-spec Team: spec and removed T-spec Team: spec labels Jul 24, 2024
src/abi.md Show resolved Hide resolved
src/abi.md Outdated
* There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatuble* with `U`,

> [!NOTE]
> These properties ensure that *abi compatibility* is an equivalence relation.
Copy link
Member

@pnkfelix pnkfelix Jul 25, 2024

Choose a reason for hiding this comment

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

Consider adding the terms "reflexivity", "symmetry", and "transitivity" to the three bullets above, especially since you use at least the term "transitivity' in the text that follows.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably a good idea. I wouldn't want to put it on the bullets though, maybe add it to the note.

These properties are respectively called "reflexivity", "symmetry", and "transitivity". They ensure that abi compatibility is an equivalence relation.

src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated

fn main(){
let f: unsafe fn(*mut ()) = unsafe{core::mem::transmute(foo as unsafe fn(_))}; // Type Erase the function
let mut val = 0;
Copy link
Member

Choose a reason for hiding this comment

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

this example is relying on i32 being the fallback integer type when there is no other alternative being imposed, right?

(E.g., if one had written 5_i8 down below, then that ends up affecting the type inferred for val, and yields UB overall since now the write will be out-of-bounds, at least according to miri.)

I am wondering whether it would be better, for purposes of this example, to explicitly assign the i32 type via let val: i32 = 0; and then you avoid discussion of how integer type fallback is handled in this part of the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably, yeah. I guess my brain was just on autopilot writing that test.

src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated


r[abi.compatibility.fn-ptr]
An [`fn`-ptr type] `T` is compatible with an [`fn`-ptr type] `U` if `T` and `U` have *abi compatible* tags.
Copy link
Member

@pnkfelix pnkfelix Jul 25, 2024

Choose a reason for hiding this comment

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

is this supposed to say *abi compatible* or just compatible ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That one is supposed to say abi compatible, yes.

@chorman0773
Copy link
Contributor Author

We need to make mdbook-spec linkify Result<T,S>

Copy link
Contributor

@ehuss ehuss left a comment

Choose a reason for hiding this comment

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

Thanks @chorman0773! I really appreciate this!

src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated
```

r[abi.symbol-name.names]
The *`no_mangle` attribute* and the *`export_name` attribute* shall only be applied to a `static` or `fn` item. The *`export_name` attribute* shall not be applied to an item declared within an [`extern` block].
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't no_mangle be applied to all other items?

src/abi.md Outdated Show resolved Hide resolved
src/abi.md Outdated
@@ -79,22 +344,46 @@ The *`link_section` attribute* specifies the section of the object file that a
pub static VAR1: u32 = 1;
```

## The `export_name` attribute
r[abi.link_section.def]
An item with the *`link_section` attribute* is placed in the specified section when linking. The section specified shall not violate the constraints on section names on the target, and shall not be invalid for the item type, no diagnostic is required.
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to our conversation before about ndr, I think it would be best to avoid this for now until we have a decision on it.

src/abi.md Outdated
exported on a [function] or [static]. It uses the [_MetaNameValueStr_] syntax
to specify the symbol name.
> [!NOTE]
> A section name may be invalid if it violates the requirements for the item type, for example, an `fn` item must be placed in an executable section, and a mutable static item (`static mut` or one containing an `UnsafeCell`) must be placed in a writable section.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
> A section name may be invalid if it violates the requirements for the item type, for example, an `fn` item must be placed in an executable section, and a mutable static item (`static mut` or one containing an `UnsafeCell`) must be placed in a writable section.
> A section name may be invalid if it violates the requirements for the item type. For example, an `fn` item must be placed in an executable section, and a mutable static item (`static mut` or one containing an `UnsafeCell`) must be placed in a writable section.

src/abi.md Show resolved Hide resolved
@ehuss
Copy link
Contributor

ehuss commented Jul 26, 2024

We need to make mdbook-spec linkify Result<T,S>

For now, you'll need to use a fully qualified path like [`Result<T, S>`](std::result::Result). It's not really possible to support prelude items, since it needs some kind of token (like std::) to know if it is a standard library link.

@chorman0773
Copy link
Contributor Author

That's current what I'm using - the issue is on the <T,S>. It seems to handle 1 generic parameter fine, but not 2.

@ehuss
Copy link
Contributor

ehuss commented Jul 26, 2024

Ah, I see! Posted #1549 with a fix.

@ehuss
Copy link
Contributor

ehuss commented Jul 30, 2024

A concern that I think we should consider is that this seems to duplicate content from the core documentation. I think this is an important question about how we want to handle that. There are a few options:

  • Move everything to the reference, and remove from the core docs and link to the reference.
  • Keep everything in the core docs, and don't add it to the reference.
  • Duplicate in both places.

I think if it is duplicated, it will get out of sync, which I think will contribute to confusion, and cause more work.

I lean towards moving it to the reference, but there are some considerations of it being very useful to be in the core docs.

@traviscross
Copy link
Contributor

cc @RalfJung

@workingjubilee
Copy link
Member

I lean towards moving it to the reference, but there are some considerations of it being very useful to be in the core docs.

I think that where it is relevant, some things should be documented in the standard library even at the cost of duplication and even at the cost of desync.

Tersely, and then immediately (ahem) reference the Reference.

@workingjubilee
Copy link
Member

This probably could afford splitting the attributes and argument/return type equivalence into different files?

@ehuss
Copy link
Contributor

ehuss commented Sep 21, 2024

cc rust-lang/rust#130653

@traviscross
Copy link
Contributor

cc @rust-lang/opsem

@ehuss
Copy link
Contributor

ehuss commented Oct 21, 2024

Can you update to also include rust-lang/rust#128784 (assuming that isn't already covered, and should go here and not elsewhere)?

@ehuss
Copy link
Contributor

ehuss commented Oct 21, 2024

Does this also need to be updated for rust-lang/rust#110503?

@chorman0773
Copy link
Contributor Author

chorman0773 commented Oct 21, 2024

rust-lang/rust#128784 seems more like something for the items/extern-block.md, as the list of supported ABI strings are documented in that chapter.

Does this also need to be updated for rust-lang/rust#110503?

Hmm... I can't tell whether the FCP in rust-lang/rust#130628 provides a just the Layout guarantee for all types or an ABI guarantee, so I'd like for T-lang to clarify that.

@rustbot label: +I-lang-nominated

Question for T-lang: In rust#130628, T-lang FCP-stabilized a layout guarantee for any enum type that matches the specific form documented there in rust-lang/rust#130628 (comment). The layout guarantee will be documented in #1654. Does this layout guarantee also carry an ABI compatibility guarantee that should be documented here?

@traviscross
Copy link
Contributor

@rustbot labels -I-lang-nominated

Good catch that we didn't do a great job of being clear about that in writing up the FCP. We did mean, though, for this to be an ABI guarantee (e.g., we were building on @RalfJung's comment here).

We're documenting this also in:

… abi compatible with their *elision candidate field*s
@chorman0773
Copy link
Contributor Author

The new section points to Ralf's UCG chapter temporarily, but the link can be removed and pointed to the id defined by #1654.

linking external libraries.

## ABI compatibility

r[abi.compatibility]
Copy link
Member

Choose a reason for hiding this comment

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

There's no paragraph after this marker... is this the normal syntax?

r[abi.compatibility]

r[abi.compatibility.intro]
Function calls pass parameters and return values between the caller and the callee function. This requires the caller and callee to agree on an ABI for those parameters and return values. This is typically only guaranteed when the same type is used in both the call site and the definition site of the callee, but certain other types may be *abi compatible*. This can appear when transmuting a [function pointer] or using an [`extern` block] to call a function. When the parameters or return types differ between the call site and def site, assuming they are *abi compatible*, the parameters or return types are transmuted to the type at the def site or call site respectively.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Function calls pass parameters and return values between the caller and the callee function. This requires the caller and callee to agree on an ABI for those parameters and return values. This is typically only guaranteed when the same type is used in both the call site and the definition site of the callee, but certain other types may be *abi compatible*. This can appear when transmuting a [function pointer] or using an [`extern` block] to call a function. When the parameters or return types differ between the call site and def site, assuming they are *abi compatible*, the parameters or return types are transmuted to the type at the def site or call site respectively.
Function calls pass parameters and return values between the caller and the callee function. This requires the caller and callee to agree on an ABI for those parameters and return values. This is typically only guaranteed when the same type is used in both the call site and the definition site of the callee. However, differences between caller and callee types can appear when transmuting a [function pointer] or using an [`extern` block] to call a function. This is permitted if the caller and callee types are *abi compatible* (otherwise, it is undefined behavior). If the types are abi compatible, the parameters are transmuted to the callee type as part of the call and the return value is transmuted to the caller type upon return.

Function calls pass parameters and return values between the caller and the callee function. This requires the caller and callee to agree on an ABI for those parameters and return values. This is typically only guaranteed when the same type is used in both the call site and the definition site of the callee, but certain other types may be *abi compatible*. This can appear when transmuting a [function pointer] or using an [`extern` block] to call a function. When the parameters or return types differ between the call site and def site, assuming they are *abi compatible*, the parameters or return types are transmuted to the type at the def site or call site respectively.

> [!NOTE]
> This can include calls to functions defined outside of rust, or built using a different Rust compiler version.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
> This can include calls to functions defined outside of rust, or built using a different Rust compiler version.
> This can include calls to functions defined outside of Rust, or built using a different Rust compiler version.

> [!NOTE]
> This can include calls to functions defined outside of rust, or built using a different Rust compiler version.
> Additional guarantees will apply in this case for "FFI Safe" types, which match up with the platform C ABI in well-defined ways.
> These are not fully documented here currently.
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this say that additional requirements apply? The document right now only describes the rules for Rust-to-Rust calls, as far as I can see.

Comment on lines +29 to +33
r[abi.compatibility.equivalence]
Two types `T` and `U` are *abi compatible* if:
* They are the same type,
* `U` is *abi compatible* with `T`, or
* There exists a type `V`, such that `T` is *abi compatible* with `V` an `V` is *abi compatible* with `U`,
Copy link
Member

Choose a reason for hiding this comment

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

IMO this is better stated after all the other clauses, since really what we are doing is we are generating a relation by having some "seeds" and then we are upclosing it to become an equivalence relation. It is quite confusing to read this before we added any of the elements to the relation that make it interesting.

```

r[abi.compatibility.core]
The types [`core::mem::MaybeUninit<T>`], [`core::cell::UnsafeCell<T>`], and [`core::num::NonZero<T>`], are *abi compatible* with `T`.
Copy link
Member

Choose a reason for hiding this comment

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

This is odd... why do we list these types and not others?

> Due to transitivity, two such types are *abi compatible* with each other if their *elision candidate field*s are *abi comaptible*

r[abi.compatibility.fn-ptr]
An [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
An [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags.
A [function pointer] type `T` is *abi compatible* with an [function pointer] type `U` if `T` and `U` have *abi compatible* tags.

> [!NOTE]
> A signature is compatible with itself.

r[abi.compatibility.simd-abi]
Copy link
Member

Choose a reason for hiding this comment

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

Given that we consider this a bug and are very close to fixing the bug to at least emit warnings, I don't think we should list this here.

* The ABI tag of the signature is `extern "Rust"`, or
* If any parameter type, the return type, or the type of any argument passed via C-varargs has *simd abi requirements*, each [*salient target features*][target_feature] of that type is either set at both the definition site of the function, and at the call site, or is set at neither site.

The behavior of a call that is not valid is undefined.
Copy link
Member

Choose a reason for hiding this comment

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

Should this say that a valid call transmutes the arguments / return value?

Two types, `T` and `U`, are *abi compatible* if both have size 0 and alignment 1.

r[abi.compatibility.discriminant]
If `T` is an a type listed in [layout.repr.rust.option.elision], and `U` is the type of the *elision candidate field*, then `T` is layout compatible with `U`.
Copy link
Member

Choose a reason for hiding this comment

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

The referenced section here doesn't exist yet, does it?

Copy link
Member

Choose a reason for hiding this comment

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

Oh this is just a normal markdown link for now, I see.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-abi Area: ABI S-waiting-on-review Status: The marked PR is awaiting review from the PR author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants