rust-lang/rust · error

last arg

Error message

last arg

What it means

`new_args.pop().expect("last arg")` in the `__builtin_ia32_{add,sub,mul,div,max,min}{ps,pd}512_mask` arm. The adapter relocates the caller's trailing rounding/sae argument to the end (after inserting an undefined src and an all-ones mask) to match GCC's parameter order. It panics if the incoming `args` slice is empty, which only happens when an LLVM intrinsic routed here was called with no arguments — i.e. the intrinsic definition in rustc drifted from the GCC adapter's expected arity.

Source

Thrown at compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs:402

                    new_args.push(last_arg);
                }

                args = new_args.into();
            }
            "__builtin_ia32_addps512_mask"
            | "__builtin_ia32_addpd512_mask"
            | "__builtin_ia32_subps512_mask"
            | "__builtin_ia32_subpd512_mask"
            | "__builtin_ia32_mulps512_mask"
            | "__builtin_ia32_mulpd512_mask"
            | "__builtin_ia32_divps512_mask"
            | "__builtin_ia32_divpd512_mask"
            | "__builtin_ia32_maxps512_mask"
            | "__builtin_ia32_maxpd512_mask"
            | "__builtin_ia32_minps512_mask"
            | "__builtin_ia32_minpd512_mask" => {
                let mut new_args = args.to_vec();
                let last_arg = new_args.pop().expect("last arg");
                let arg3_type = gcc_func.get_param_type(2);
                let undefined = builder
                    .current_func()
                    .new_local(None, arg3_type, "undefined_for_intrinsic")
                    .to_rvalue();
                new_args.push(undefined);
                let arg4_type = gcc_func.get_param_type(3);
                let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1);
                new_args.push(minus_one);
                new_args.push(last_arg);
                args = new_args.into();
            }
            "__builtin_ia32_vfmaddsubps512_mask"
            | "__builtin_ia32_vfmaddsubpd512_mask"
            | "__builtin_ia32_cmpsh_mask_round"
            | "__builtin_ia32_vfmaddph512_mask"
            | "__builtin_ia32_vfmaddsubph512_mask" => {
                let mut new_args = args.to_vec();

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Ensure rustc_codegen_gcc backend revision matches the rustc toolchain it was built for.
  2. Pin the toolchain with `rustup default <matching-version>` or rust-toolchain.toml.
  3. Rebuild the backend from a commit that supports the current rustc intrinsic definitions.
  4. Avoid hand-written `llvm.x86.avx512.*.512` intrinsics; prefer `core::arch::x86_64::_mm512_*` which carry the correct arity.

Example fix

// before (intrinsic/llvm.rs:402)
let last_arg = new_args.pop().expect("last arg");

// after
let Some(last_arg) = new_args.pop() else {
    sess.dcx().fatal(format!(
        "`{}` reached masked arm with no rounding argument; \
         rustc/GCC intrinsic arity mismatch",
        gcc_func.get_name()
    ));
};
Defensive patterns

Strategy: validation

Validate before calling

// Validate argument count before invoking AVX-512 arithmetic intrinsics
// The GCC backend pops the last arg; if args is empty, it panics.
fn validate_intrinsic_argc(name: &str, args_provided: usize) -> Result<(), String> {
    let required = match name {
        "llvm.x86.avx512.add.ps.512"
        | "llvm.x86.avx512.add.pd.512"
        | "llvm.x86.avx512.sub.ps.512"
        | "llvm.x86.avx512.mul.ps.512"
        | "llvm.x86.avx512.div.ps.512"
        | "llvm.x86.avx512.max.ps.512"
        | "llvm.x86.avx512.min.ps.512" => 3, // src1, src2, rounding_control
        _ => return Ok(()),
    };
    if args_provided < required {
        return Err(format!(
            "{} requires at least {} args but got {}",
            name, required, args_provided
        ));
    }
    Ok(())
}

// In build.rs: probe whether the GCC backend handles your intrinsics
fn gcc_backend_probe() -> Result<(), String> {
    let out = std::process::Command::new("rustc")
        .args(["-Z", "codegen-backend=gcc", "--crate-type=lib", "-", "-o", "/dev/null"])
        .stdin(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .spawn()
        .map_err(|e| format!("Cannot spawn rustc: {}", e))?;
    // Feed a minimal AVX-512 test crate and check for panic
    // If it panics, fall back to LLVM backend
    Ok(())
}

Prevention

When it happens

Trigger: Code lowering `llvm.x86.avx512.add.ps.512` / `pd.512` (and sub/mul/div/max/min) through rustc_codegen_gcc when rustc passes an argument list shorter than the adapter assumes, or when a non-masked form is incorrectly routed into the masked arm.

Common situations: Mismatched rustc/rustc_codegen_gcc checkout, a half-applied refactor of an LLVM intrinsic arity, or calling a raw `llvm.x86.avx512.*` intrinsic with a malformed argument list. End users hit it mainly after a rustup that bumped rustc past the rustc_codegen_gcc backend's supported version.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/2cef4f0cbd0d91d5.json. Report an issue: GitHub.