rust-lang/rust · error
Architecture {arch} does not support GpuKernel calling conve
Error message
Architecture {arch} does not support GpuKernel calling convention What it means
`panic!("Architecture {arch} does not support GpuKernel calling convention")` in `to_llvm_calling_convention` for `CanonAbi::GpuKernel`. LLVM only assigns a kernel calling convention for `Arch::AmdGpu` (`llvm::AmdgpuKernel`) and `Arch::Nvptx64` (`llvm::PtxKernel`); any other target arch hits the catch-all and aborts. It fires when source declares `extern "gpu-kernel"` (the kernel ABI used by `rustc`'s GPU targets) but is being compiled for a non-GPU target.
Source
Thrown at compiler/rustc_codegen_llvm/src/abi.rs:740
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
CanonAbi::RustCold => llvm::PreserveMost,
CanonAbi::RustPreserveNone => match &sess.target.arch {
Arch::X86_64 | Arch::AArch64 => llvm::PreserveNone,
_ => llvm::CCallConv,
},
CanonAbi::RustTail => match &sess.target.arch {
Arch::X86 | Arch::X86_64 | Arch::AArch64 => llvm::Tail,
_ => sess.dcx().fatal("extern \"tail\" is only supported on x86, x86_64 and aarch64"),
},
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
CanonAbi::Custom => llvm::CCallConv,
CanonAbi::Swift => llvm::SwiftCallConv,
CanonAbi::GpuKernel => match &sess.target.arch {
Arch::AmdGpu => llvm::AmdgpuKernel,
Arch::Nvptx64 => llvm::PtxKernel,
arch => panic!("Architecture {arch} does not support GpuKernel calling convention"),
},
CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
InterruptKind::Avr => llvm::AvrInterrupt,
InterruptKind::AvrNonBlocking => llvm::AvrNonBlockingInterrupt,
InterruptKind::Msp430 => llvm::Msp430Intr,
InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => llvm::CCallConv,
InterruptKind::X86 => llvm::X86_Intr,
},
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::Aapcs => llvm::ArmAapcsCallConv,
ArmCall::CCmseNonSecureCall | ArmCall::CCmseNonSecureEntry => llvm::CCallConv,
},
CanonAbi::X86(x86_call) => match x86_call {
X86Call::Fastcall => llvm::X86FastcallCallConv,
X86Call::Stdcall => llvm::X86StdcallCallConv,
X86Call::SysV64 => llvm::X86_64_SysV,
X86Call::Thiscall => llvm::X86_ThisCall,
X86Call::Vectorcall => llvm::X86_VectorCall,View on GitHub (pinned to 22057b88b0)
Solutions
- Set the target triple to a GPU target: `--target amdgcn-amd-amdhsa` or `--target nvptx64-nvidia-cuda`.
- Gate `extern "gpu-kernel"` items behind `#[cfg(target_arch = "amdgpu")]` / `#[cfg(target_arch = "nvptx64")]`.
- Split GPU kernel code into a separate crate compiled only for the GPU target; keep host crates free of the ABI.
- If using rust-gpu / a build script, ensure it emits the kernel target and does not also build for the host arch.
Example fix
// before
extern "gpu-kernel" fn add(a: f32, b: f32) -> f32 { a + b }
// after — only emit the kernel ABI on GPU targets
#[cfg(any(target_arch = "amdgpu", target_arch = "nvptx64"))]
extern "gpu-kernel" fn add(a: f32, b: f32) -> f32 { a + b }
#[cfg(not(any(target_arch = "amdgpu", target_arch = "nvptx64")))]
compile_error!("`add` is a GPU kernel; compile with a gpu target"); Defensive patterns
Strategy: validation
Validate before calling
// Validate target architecture before using extern "gpu-kernel" ABI
fn supports_gpu_kernel(arch: &str) -> bool {
matches!(arch, "amdgcn" | "nvptx64")
}
fn validate_gpu_target() -> Result<(), String> {
let arch = std::env::var("CARGO_CFG_TARGET_ARCH")
.or_else(|_| std::env::var("TARGET_ARCH"))
.map_err(|_| "TARGET_ARCH not set")?;
if !supports_gpu_kernel(&arch) {
return Err(format!(
"Architecture '{}' does not support GpuKernel calling convention. \
Supported: amdgcn, nvptx64. Compile with --target nvptx64-nvidia-cuda \
or amdgcn-amd-amdhsa.",
arch
));
}
Ok(())
} Prevention
- Gate GPU kernel functions behind #[cfg(target_arch = "nvptx64")] or #[cfg(target_arch = "amdgcn")] so they only compile for GPU targets
- Provide a CPU fallback implementation under #[cfg(not(any(target_arch = "nvptx64", target_arch = "amdgcn")))]
- Always specify --target explicitly (e.g. cargo build --target nvptx64-nvidia-cuda) rather than relying on host defaults
- Check CARGO_CFG_TARGET_ARCH in build.rs and fail early with a clear message instead of letting the compiler panic mid-build
When it happens
Trigger: An `extern "gpu-kernel" fn` (or a crate that exposes one) is compiled with `--target` set to x86_64, aarch64, wasm32, etc. instead of an `amdgcn-*` or `nvptx64-*` target triple. Also triggered by proc-macro/host builds of GPU kernel crates that don't gate the ABI behind `#[cfg(target_arch = "amdgpu" | "nvptx64")]`.
Common situations: Building a GPU crate (e.g. a `rust-gpu`/CUDA/ROCm kernel) without setting the right `--target`; CI building the host crate graph and accidentally compiling GPU-only code; a generic library that re-exports a `gpu-kernel` ABI symbol for all targets.
Related errors
- `is_signed` on non-scalar ABI {self:?}
- got a non-UTF8 data-layout from LLVM
- This rustc version was not built with LLVM Offload support!
- unsupported integer: {self:?}
- unsupported float: {self:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/1a9d0641084b954a.json.
Report an issue: GitHub.