Skip to content

Tracking issue for unsupported_calling_conventions #137018

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

Open
RalfJung opened this issue Feb 14, 2025 · 23 comments
Open

Tracking issue for unsupported_calling_conventions #137018

RalfJung opened this issue Feb 14, 2025 · 23 comments
Labels
A-ABI Area: Concerning the application binary interface (ABI) C-bug Category: This is a bug. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC I-lang-radar Items that are on lang's radar and will need eventual work or consideration. O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team

Comments

@RalfJung
Copy link
Member

RalfJung commented Feb 14, 2025

This is a tracking issue for the unsupported_calling_conventions lint. This lint warns against

  • Using extern "cdecl" on non-x86-32 targets. Use extern "C" instead, there is no difference in behavior.
  • Using extern "stdcall" or extern "fastcall" on non-x86-32 Windows targets. These ABIs are only defined for x86-32.
    • If you want to use "stdcall on x86-32-windows, C everywhere else", then use extern "system".
    • Otherwise, if you really need the same function both on x86-32 and on other targets but with a different ABI, consider using the fn_abi crate. Also we'd be interested to hear about your use-case, so please leave a comment below.

Implementation history:

Timeline:

  • This was introduced with Rust 1.89.
  • There's no timeline yet for when this will show up in cargo's future-compat reports, or be turned into a hard error. Since windows-sys needs an update to v0.60 to avoid the lint, we'll have to move really slowly here.

Original issue description

We generally accept stdcall on non-x86-32 Windows targets (while rejecting it on other non-x86-32 targets). See the discussion about this at #86231 (comment) and #86231 (comment). However, @ChrisDenton points out that the raw-dylib feature is more strict here. That's an inconsistency that we should probably fix?

@ChrisDenton can you give an example of what exactly is being rejected by raw-dylib here?

2025-05-05: See here for the current latest proposal.

Cc @workingjubilee @rust-lang/lang @nagisa @petrochenkov

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Feb 14, 2025
@workingjubilee workingjubilee added O-windows Operating system: Windows A-ABI Area: Concerning the application binary interface (ABI) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team labels Feb 14, 2025
@ChrisDenton
Copy link
Member

It's just generally more strict. As far as I recall this is intentional, cc @dpaoliello. For example:

#[link(name = "library", kind = "raw-dylib")]
extern "cdecl" { // or stdcall
    fn test();
}

This is rejected on x86_64-pc-windows-msvc and aarch64-pc-windows-msvc. But remove kind = "raw-dylib" and it works.

@RalfJung
Copy link
Member Author

RalfJung commented Feb 14, 2025 via email

@Aditya-PS-05

This comment has been minimized.

@RalfJung
Copy link
Member Author

RalfJung commented Feb 14, 2025

@Aditya-PS-05 currently this issue is about discussing what to do next; there is no agreed-upon plan for what to do yet.


Reading the past comments, it seems like ~noone argued in favor of the status quo. So maybe the best next step is to have a FCW lint against

  • stdcall, fastcall on everything but 32-bit x86
  • vectorcall on everything but x86 (32bit or 64bit)
  • EDIT: cdecl on everything but 32-bit x86

This should probably re-introduce the lint that was removed in #129935.

@ChrisDenton also mentioned cdecl above; I did not have that on my radar yet. Currently, that one is accepted everywhere. Which targets should it support?

Either way, raw-dylib shouldn't have its own "does this ABI make sense" logic (currently located here); it should call is_abi_supported like everything else. (But that function might return a three-state value to indicate "not really but for backwards compatibility we accept this in some cases; and raw-dylib can then make a hard error rather than an FCW for those.)

@Aditya-PS-05

This comment has been minimized.

@ChrisDenton

This comment has been minimized.

@dpaoliello
Copy link
Contributor

It's just generally more strict. As far as I recall this is intentional, cc @dpaoliello.

Yes, it was intentional, although I would describe it more as "let's start restrictive and we'll loosen things later" rather than "this is the absolute correct behavior": #86419 (comment)

Either way, raw-dylib shouldn't have its own "does this ABI make sense" logic (currently located here); it should call is_abi_supported like everything else.

raw-dylib has its own logic for historical reasons: primarily that it wasn't supported for all calling conventions or all arches for a while, hence its own logic to filter to what it did support.

Personally, I'm going to bow out of this discussion. I previously said that having this behavior would cause a proliferation of cfg_attr attributes without a huge benefit to safety or correctness but was told that #87678 would eventually be an error and so this would be moot: https://rust-lang.zulipchat.com/#narrow/channel/233931-t-compiler.2Fmajor-changes/topic/Add.20import_name_type.20parameter.20to.20.23.5Blink.5D.20compiler-team.23525

@RalfJung
Copy link
Member Author

RalfJung commented Feb 14, 2025

I previously said that having this behavior would cause a proliferation of cfg_attr attributes without a huge benefit to safety or correctness

Not sure what exactly you are referring to with "this behavior". Maybe this part of your Zulip message?

If using stdcall is an error on x86_64, then I have no idea how you'd write this without duplicating the entire extern block...

For the case of "stdcall on win32, C everywhere else", we have the system ABI, so for this case forbidding "stdcall" on non-x86 would not cause any duplication.

@RalfJung
Copy link
Member Author

"cdecl" is an ABI that we have supported since pre-1.0, but it is implemented as a complete alias for C. Nominally this is the name of a particular x86 ABI, so we should probably deprecate this on all non-x86 targets together with the others mentioned above.

@jieyouxu jieyouxu removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Feb 14, 2025
@RalfJung RalfJung changed the title Handling of stdcall on non-x86-32 Windows targets is inconsistent Handling of stdcall (and other x86-32-specific ABIs) on non-x86-32 Windows targets is inconsistent Feb 20, 2025
@RalfJung
Copy link
Member Author

RalfJung commented Feb 20, 2025

@ChrisDenton

Knowing the history here and the reasons behind those decisions is the first step.

I'm pretty sure the history is

  • way before Rust 1.0 we didn't think about this very carefully so we just allowed all ABIs everywhere
  • at some point we started having a notion of some ABIs only working on specific architectures / targets, but for backwards compatibility all the existing ABIs were grandfathered in
  • Replace per-target ABI denylist with an allowlist #86231 started cleaning this up for some ABIs, but @nagisa didn't want to reject more cases since "I feel like a change like this will want an input from T-lang and perhaps some sort of an FCP" (source)

So... I would propose we ask t-lang to approve the intention of completing what was started in #86231. The goal would be:

  • thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
  • vectorcall should only be accepted on x86-32 and x86-64

The status quo is:

  • thiscall is only accepted on x86-32 (this one is already correct 🎉 )
  • cdecl is accepted everywhere
  • stdcall, fastcall are accepted on x86-32 as well as on all Windows targets
  • vectorcall is accepted on x86-32 and x86-64 as well as on all Windows targets (this ABI is still gated behind abi_vectorcall, so changing it is not a breaking change)

If people want the behavior of "stdcall on win32, C everywhere else", they can use system. "cdecl" can unconditionally be replaced by "C". If they have different reasons to use any of these ABIs on targets where they don't make sense, we do not have a direct replacement (so we might learn about good use-cases for this when we start linting against this).

@ChrisDenton @workingjubilee any objections to this plan?

@ChrisDenton
Copy link
Member

I have no objections.

@nagisa
Copy link
Member

nagisa commented Feb 21, 2025

Yeah, a few years sounds like a reasonably long timeline to start thinking about the next steps here. I do recall there being some push-back against making thiscall/stdcall/fastcall work on x86-32 only on the grounds of "MSVC accepts everything everywhere and I don't want to think when rewriting my windows C code to Rust", but I personally think the world is going to be a better place if we take a principled stance here.

@RalfJung
Copy link
Member Author

RalfJung commented Feb 21, 2025

I do recall there being some push-back against making thiscall/stdcall/fastcall work on x86-32 only on the grounds of "MSVC accepts everything everywhere and I don't want to think when rewriting my windows C code to Rust"

Do you have a link to that? In the final PR, so far I only saw @petrochenkov also asking for the ABIs to be rejected on other targets.

Also note that thiscall is already x86-32-only. I couldn't find a record in our bugtracker of anyone complaining about that.

@ChrisDenton
Copy link
Member

I do wish we had a nicer way for users to select ABI based on target that doesn't involve either duplicating a lot of unrelated code or putting the entire extern block in a macro. I think that would have made the decision here a lot easier.

@RalfJung
Copy link
Member Author

I seem to recall there was a proposal once for allowing macros in the ABI string position, which would make this slightly less annoying albeit still a bit awkward.

@RalfJung
Copy link
Member Author

RalfJung commented May 5, 2025

Based on the above, nominating for @rust-lang/lang. The question is about what to do with architecture-specific ABI strings like "stdcall" when they are used on other architectures where there is no such ABI. The concrete proposal is here. This is a breaking change similar in nature to #86231.

The potential downside here is that if someone writes Windows-only code that needs to write/call a function with the ABI "fastcall on x86-32, C everywhere else", that could no longer be easily expressed. This is very specific though:

  • "fastcall" already gets rejected on targets that are not(any(x86-32, windows)), so this can only really be a new problem for Windows-only code.
  • The proposal is to make "fastcall" and "stdcall" consistent with how "thiscall" already behaves: "thiscall" already gets rejected on non-x86-32 targets, and I was not able to find people complaining about this. This did come up during "thiscall" stabilization (see this and surrounding comments), but since then whatever we currently provide seems to be "good enough". There's a nice crate for dealing with the case of swapping out the ABI of an extern block using cfg conditions.
  • If you need "stdcall on x86-32-windows, C everywhere else", we got you covered: use the "system" ABI.

@RalfJung RalfJung added the I-lang-nominated Nominated for discussion during a lang team meeting. label May 5, 2025
@mati865

This comment has been minimized.

@RalfJung

This comment has been minimized.

@mati865

This comment has been minimized.

@joshtriplett
Copy link
Member

joshtriplett commented May 7, 2025

Broadly speaking, I'd favor allowing this and having a warn-by-default lint when using it, as several people have suggested. I don't have any strong feelings about whether it's an FCW and we eventually disallow it, or whether it's a lint and we allow it indefinitely.

EDIT: I think extern "system" addresses this use case effectively; suggestion withdrawn.

@RalfJung
Copy link
Member Author

RalfJung commented May 7, 2025 via email

@traviscross
Copy link
Contributor

traviscross commented May 8, 2025

@rustbot labels -I-lang-nominated +I-lang-radar

We talked about this in the lang call today, and with 3/5 present, we were directionally aligned with being stricter here, as outlined in the plan above.

We weren't sure in discussion whether it would worth all the steps that would be needed to make this a hard error (e.g. FCW, crater run, PRs to affected projects, etc.), but of course, if people are happy to do that work, we're happy to consider the proposals for the steps we'd need to approve.

@rustbot rustbot added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed I-lang-nominated Nominated for discussion during a lang team meeting. labels May 8, 2025
@RalfJung
Copy link
Member Author

RalfJung commented May 8, 2025

A crater run is unfortunately unlikely to be very useful since the change mostly affects Windows targets -- only "cdecl" also affects non-Windows targets.

@RalfJung RalfJung added the C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC label May 23, 2025
@RalfJung RalfJung changed the title Handling of stdcall (and other x86-32-specific ABIs) on non-x86-32 Windows targets is inconsistent Tracking issue for unsupported_calling_conventions Jun 7, 2025
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Jun 7, 2025
…ntions, r=workingjubilee

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in rust-lang#129935, in order to start the process of dealing with rust-lang#137018. Specifically, we are going for the plan laid out [here](rust-lang#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue Jun 7, 2025
…ntions, r=workingjubilee

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in rust-lang#129935, in order to start the process of dealing with rust-lang#137018. Specifically, we are going for the plan laid out [here](rust-lang#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.
rust-bors bot added a commit that referenced this issue Jun 7, 2025
…try>

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in #129935, in order to start the process of dealing with #137018. Specifically, we are going for the plan laid out [here](#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.

try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: test-various
rust-bors bot added a commit that referenced this issue Jun 8, 2025
…try>

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in #129935, in order to start the process of dealing with #137018. Specifically, we are going for the plan laid out [here](#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.

try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: test-various
rust-bors bot added a commit that referenced this issue Jun 8, 2025
…try>

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in #129935, in order to start the process of dealing with #137018. Specifically, we are going for the plan laid out [here](#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.

try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: test-various
rust-bors bot added a commit that referenced this issue Jun 8, 2025
…try>

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in #129935, in order to start the process of dealing with #137018. Specifically, we are going for the plan laid out [here](#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.

try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: test-various
bors added a commit that referenced this issue Jun 9, 2025
…orkingjubilee

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in #129935, in order to start the process of dealing with #137018. Specifically, we are going for the plan laid out [here](#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.

try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: test-various
lnicola pushed a commit to lnicola/rust-analyzer that referenced this issue Jun 9, 2025
…orkingjubilee

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in rust-lang/rust#129935, in order to start the process of dealing with rust-lang/rust#137018. Specifically, we are going for the plan laid out [here](rust-lang/rust#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.

try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: test-various
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Jun 10, 2025
…orkingjubilee

Add (back) `unsupported_calling_conventions` lint to reject more invalid calling conventions

This adds back the `unsupported_calling_conventions` lint that was removed in rust-lang/rust#129935, in order to start the process of dealing with rust-lang/rust#137018. Specifically, we are going for the plan laid out [here](rust-lang/rust#137018 (comment)):
- thiscall, stdcall, fastcall, cdecl should only be accepted on x86-32
- vectorcall should only be accepted on x86-32 and x86-64

The difference to the status quo is that:
- We stop accepting stdcall, fastcall on targets that are windows && non-x86-32 (we already don't accept these on targets that are non-windows && non-x86-32)
- We stop accepting cdecl on targets that are non-x86-32
- (There is no difference for thiscall, this was already a hard error on non-x86-32)
- We stop accepting vectorcall on targets that are windows && non-x86-*

Vectorcall is an unstable ABI so we can just make this a hard error immediately. The others are stable, so we emit the `unsupported_calling_conventions` forward-compat lint. I set up the lint to show up in dependencies via cargo's future-compat report immediately, but we could also make it show up just for the local crate first if that is preferred.

try-job: i686-msvc-1
try-job: x86_64-msvc-1
try-job: test-various
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ABI Area: Concerning the application binary interface (ABI) C-bug Category: This is a bug. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC I-lang-radar Items that are on lang's radar and will need eventual work or consideration. O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team
Projects
None yet
Development

No branches or pull requests