One simple improvement would be having the compiler issue an error if you either:

1. Combine a cross-platform ABI with any single-platform ABIs
2. Specify multiple single-platform ABIs that apply to the same platform.

That's very easy.

Oh, and two function types are only compatible if the ABI set is identical.


Niko

March 13, 2013 12:02 PM




Well, doing a bit more web searching, perhaps you can perhaps just attach attributes to function types in the same way.  There is very little discussion of this, to be sure.

Anyhow, just to spell out what I left implied in my previous e-mail, the alternative to that proposal is to allow multiple ABIs to be listed, and you just use the (first?) one that applies to the current target architecture.  So `extern "stdcall aapcs" fn(...) -> ...` would cover the example I gave before.  That's not too hard to implement, actually, so maybe that's the way to go.  It avoids the need for duplicate modules and #[cfg] tricks, which I hate, and it's really almost no extra work in the compiler.  It'd still be the case that `extern "C"` and `extern "Rust"` are the normal common cases: C would basically be shorthand for `cdecl aapcs` (plus whatever the defaults are on other architectures, like MIPS).

So far this is my preferred plan.  To summarize:

- Uppercase names "C" and "Rust" for "cross-platform" ABIs
- Lowercase names for other, platform-specific ABIs
- Multiple ABIs are permitted, compiler will use the first that applies to the target architecture
- Invoking an extern function without a suitable ABI for the current target is an error

If this doesn't seem agreeable to anyone, let me know :)


Niko
March 13, 2013 11:54 AM
So, an alternative possibility might be:

- Use Uppercase ABI names to indicate broad, "cross-platform" variants (e.g., C, Rust).
- Use lowercase ABI names to indicate platform-specific variations (e.g., cdecl, stdcall, fastcall, aapcs).

Each platform must define what it means to be a "C" function or "Rust" function (presumably: cdecl on x86, aapcs on ARM). Then the preferred thing would be to do `extern "C" fn()` and so forth.  But you can use the lowercase variants if that is necessary for some reason.

Invoking a function whose ABI is not defined for the current target (e.g., an attempt to call a stdcall function on ARM) would be a compile-time error.

Most of the time this means you just use `extern "C"` and things will work.  For weirder cases where something is somehow `stdcall` on x86 but `aapcs` on ARM (if such a thing ever happens), you can use #[cfg] directives.  I envision a pattern like:

    #[cfg(target=x86)] // or whatever
    mod TheFn {
        type T = extern "stdcall" fn(...) -> ...;
        extern "stdcall" { fn the_fn(...) -> ...; }
    }

    #[cfg(target=aapcs)] // or whatever
    mod TheFn {
        type T = extern "aapcs" fn(...) -> ...;
        extern "stdcall" { fn the_fn(...) -> ...; }
 
    }

Now I can refer to `TheFn::T` as the appropriate type of `TheFn` and `TheFn::the_fn()` to call it.  A touch verbose but I honestly don't know where if ever this situation arises (maybe a port of Windows to some other architecture?)

gcc allows you to associate multiple ABIs with a function definition, one per architecture, but it is unclear to me how that interacts with e.g. function pointers.  My guess is that it just...doesn't.  Therefore I'd prefer not to do the same.
 


Niko
March 13, 2013 8:46 AM

cdecl and stdcall are definitely x86-specific. I consider the following
documentation official on the matter. (See also pcs there for ARM case.)

http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to