about summary refs log tree commit diff
path: root/compiler/rustc_interface/src/queries.rs
diff options
context:
space:
mode:
authorJubilee <workingjubilee@gmail.com>2025-06-23 12:48:20 -0700
committerGitHub <noreply@github.com>2025-06-23 12:48:20 -0700
commitff1636b6e3fb685f43b17be8a12905203c8717da (patch)
tree4ba840f4be780a7764d9ceaeee92c5fcd127075d /compiler/rustc_interface/src/queries.rs
parentfc3d7ee7b7537cae52d3b5c3cb3d33da4e8f6652 (diff)
parentaa25b9b116fd5f6e86ae01207c3b2e76104513fa (diff)
downloadrust-ff1636b6e3fb685f43b17be8a12905203c8717da.tar.gz
rust-ff1636b6e3fb685f43b17be8a12905203c8717da.zip
Rollup merge of #142134 - workingjubilee:reject-unsupported-abi, r=jdonszelmann,RalfJung
Reject unsupported `extern "{abi}"`s consistently in all positions

Modify the handling of `extern "{abi}"` in the compiler so that it has consistent errors without regard to the position in the grammar.

## What

Implement the following breakages:
- Promote [`unsupported_fn_ptr_calling_conventions`] from a warning to a hard error
- Guarantee future edge-cases like trait declarations will not escape so that *ABIs that have already been unusable in most positions* will now be unusable in **all positions**. See "How" and "Why or Why Not" for more details.

In particular, these architecture-specific ABIs now only compile on their architectures[^4]:
  - amdgpu: "gpu-kernel"
  - arm: "aapcs", "C-cmse-nonsecure-entry", "C-cmse-nonsecure-call"
  - avr: "avr-interrupt", "avr-non-blocking-interrupt"
  - msp430: "msp430-interrupt"
  - nvptx64: "gpu-kernel", "ptx-kernel"
  - riscv32 and riscv64: "riscv-interrupt-m", "riscv-interrupt-s"
  - x86: "thiscall"
  - x86 and x86_64: "x86-interrupt"
  - x86_64: "sysv64", "win64"

ABIs that are logically x86-specific but actually permitted on all Windows targets remain permitted on Windows, as before. For non-Windows targets, they error if we had previously done so in other positions.

## How

We modify rustc_ast_lowering to prevent unsupported ABIs from leaking through the HIR without being checked for target support. They now emit hard errors for every case where we would return `Invalid` from `AbiMap::canonize_abi`. Previously ad-hoc checking on various HIR items required making sure we check every HIR item which could contain an `extern "{abi}"` string. This is a losing proposition compared to gating the lowering itself.

As a consequence, unsupported ABI strings error instead of triggering the warning `unsupported_fn_ptr_calling_conventions`. The code is also simpler compared to alternative implementations that might e.g. split on unstable vs. stable, only suffering some unavoidable complication to support the newly-revived `unsupported_calling_conventions` lint.[^5]

However, per rust-lang/rust#86232 this does cause errors for rare usages of `extern "{abi}"` that were theoretically possible to write in Rust source, without previous warning or error. For instance, trait declarations without impls were never checked. These are the exact kinds of leakages that this new approach prevents.

This differs from the following PRs:
- rust-lang/rust#141435 is orthogonal, as it adds a new lint for ABIs we have not warned on and are not touched by this PR
- rust-lang/rust#141877 is subsumed by this, in that this simply cuts out bad functionality instead of adding epicycles for stable code

## Why or Why Not

We already made the decision to issue the `unsupported_fn_ptr_calling_conventions` future compatibility warning. It has warned in dependencies since rust-lang/rust#135767, which reached stable with Rust 1.87. That was released on 2025 May 17, and it is now June. As we already had erred on these ABI strings in most other positions, and warn on stable for function pointer types, this breakage has had reasonable foreshadowing.

Upgrading the warning to an error addresses a real problem. In some cases the Rust compiler can attempt to actually compute the ABI for calling a function with an unsupported ABI. We could accept this case and compute unsupported ABIs according to some other ABI, silently[^6]. However, this obviously exposes Rust to errors in codegen. We cannot lower directly to the "obvious", target-incorrect ABI and then trust code generators like LLVM to reliably error on these cases, either.

Other considerations include:
- We could refactor the compiler to defer ABI computations, but that seems like it would suffer the "whack-a-mole" problem close to linking instead of after parsing and expansion.
- We could run a deprecation cycle for the edge cases, but we would be warning highly marginal cases, like this trait declaration without a definition that cannot be implemented without error[^9].
```rust
pub trait UsedToSneakBy {
    pub extern "gpu-kernel" fn sneaky();
}
```
- The [crater run] on this PR's draft form suggests the primary issue is with implementations on function pointers, which has already been warned on, so it does not seem like we would be benefiting any real code.
- Converting this to a hard error now, in the same cycle that we ship the reanimation of the `unsupported_calling_conventions` lint, means people who would otherwise have to deal with two lints only have to update their code in one batch. Of course, one of them is as breakage.

r? lang

Fixes rust-lang/rust#86232
Fixes rust-lang/rust#132430
Fixes rust-lang/rust#138738
Fixes rust-lang/rust#142107

[`unsupported_fn_ptr_calling_conventions`]: https://github.com/rust-lang/rust/issues/130260
[crater run]: https://github.com/rust-lang/rust/pull/142134#issuecomment-2953837506
[^9]: Upon any impl, even for provided fn within trait declarations, e.g. `pub extern "gpu-kernel" fn sneaky() {}`, different HIR types were used which would, in fact, get checked. Likewise for anything with function pointers. Thus we would be discussing deprecation cycles for code that is impotent or forewarned[^7].
[^4]: Some already will not compile, due to reaching ICEs or LLVM errors.
[^5]: That lint cannot be moved in a similar way yet because lints operate on HIR, so you cannot emit lints when the HIR has not been completely formed.
[^6]:  We already do this for all `AbiStr` we cannot parse, pretending they are `ExternAbi::Rust`, but we also emit an error to prevent reaching too far into codegen.
[^7]: It actually did appear in two cases in rustc's test suite because we are a collection of Rust edge-cases by the simple fact that we don't care if the code actually runs. These cases are being excised in 643a9d233b4f1547220134daea4bcca809302d40
Diffstat (limited to 'compiler/rustc_interface/src/queries.rs')
0 files changed, 0 insertions, 0 deletions