Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

C interop: Complex<T>

Metadata
Point of contactFolkert de Vries
StatusAccepted
Other tracking issuesN/A
Zulip channelN/A
Funding contactTrifecta Tech Foundation
compiler championFolkert de Vries
Tracking issuerust-lang/goals#761
Teamscompiler, lang, libs
Task ownersFolkert de Vries

Summary

Rust should be able to define an ABI-compatible counterpart to every signature that C can define. This is important for C interop and translation of code from C to rust, using manual FFI, and tooling like c-bindgen and c2rust. This goal closes a long-standing gap in rust’s ability to match C.

Motivation

The status quo

Today there are still a number of cases where Rust cannot, in a portable way, express type signatures that C can define.

The C _Complex type is one such missing piece. This type is conceptually just

#![allow(unused)]
fn main() {
#[repr(C)]
struct Complex<T> { 
    real: T, 
    imaginary: T 
}
}

But many ABI pass Complex<{float}> and Complex<{int}> in a custom way, different from the equivalent C struct. The value of Complex<T> as a built-in type is that we can match those ABIs.

use core::ffi::c_double;

unsafe extern "C" {
    // Complex square root provided by libm.
    safe fn csqrtf(_: Complex<c_float>) -> Complex<c_float>;
}

fn main() {
    let c = Complex::new(-1.0, 0.0);
    assert_eq!(csqrtf(c), Complex::new(0.0, 1.0));
}

There is an accepted RFC (RFC 3892) for Complex<T>.

What we propose to do about it

We will add core::num::Complex, and the callconv implementations to ensure that C _Complex and Rust Complex are ABI-compatible accross targets.

There are some ABI differences between Clang and GCC. We’ve already submitted LLVM PRs for all known issues, and will try to get these merged into LLVM 24:

This project goal focusses on the internal implementation, and leaves most of the design and implementation of the std API for Complex<T> as future work.

Work items over the next year

TaskOwner(s)Notes
get LLVM PRs over the finish lineFolkert de Vries
implement core::num::ComplexFolkert de Vries
hook up intrinsics for cmul and cdivFolkert de Vries
work towards stabilizing the type for FFI purposes (keeping any controversial API unstable)Folkert de Vries
design (and maybe implement) more of the API (basic operators, methods based on https://en.cppreference.com/c/numeric/complex)Folkert de Vries

Team asks

TeamSupport levelNotes
compilerMediumThis feature touches callconv code, which requires careful review
langSmallThese new types have a new ABI
libsSmallJust a vibe check on the names and minimal APIs

Funding

PurposeCostFundedSponsor(s)
implementation work$12,000FullGoogle

Target timeline

The duration of the project is 6 months. Starting from the agreed start date (“Month 1”), the timeline we’re targeting is:

  • Month 1-3: callconv implementation work
  • Month 3-6: work towards stabilization

The expected effort for the work is 1 person-month.

Notes

  • #t-compiler > representing `_Complex`
  • LLVM has @llvm.experimental.complex.fmul.v2f64 etc. (introduced in https://reviews.llvm.org/D119284)
  • LLVM defines builtins like https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/divdc3.c which we’ll need in compiler-builtins

Frequently asked questions

How does this goal interact with the f80, f128 and c_longdouble goal

It is possible to have a Complex<c_longdouble>, which in some calling conventions needs custom ABI logic. It is a goal to make this combination work across targets.