From 68550af5b31f6f7b9434862c490a039f5d8aa6f8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 4 Jul 2026 20:30:00 +0200 Subject: [PATCH 01/10] add `Complex` type --- library/core/src/num/complex.rs | 19 +++++++++++++++++++ library/core/src/num/mod.rs | 3 +++ library/std/src/num/mod.rs | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 library/core/src/num/complex.rs diff --git a/library/core/src/num/complex.rs b/library/core/src/num/complex.rs new file mode 100644 index 0000000000000..4a4e4326f3902 --- /dev/null +++ b/library/core/src/num/complex.rs @@ -0,0 +1,19 @@ +/// A complex number. +#[derive(Clone, Copy, Debug, PartialEq)] +#[unstable(feature = "complex_numbers", issue = "154023")] +#[repr(C)] +pub struct Complex { + /// The real component. + pub re: T, + /// The imaginary component. + pub im: T, +} + +#[unstable(feature = "complex_numbers", issue = "154023")] +impl Complex { + /// Create a new complex number from a real and imaginary component. + #[must_use] + pub fn new(re: T, im: T) -> Complex { + Complex { re, im } + } +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 59dfe6bd8d9b7..21ed9b4b24d6a 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -42,6 +42,7 @@ mod int_macros; // import int_impl! #[macro_use] mod uint_macros; // import uint_impl! +mod complex; mod error; #[cfg(not(no_fp_fmt_parse))] mod float_parse; @@ -54,6 +55,8 @@ mod wrapping; #[doc(hidden)] pub mod niche_types; +#[unstable(feature = "complex_numbers", issue = "154023")] +pub use complex::Complex; #[stable(feature = "int_error_matching", since = "1.55.0")] pub use error::IntErrorKind; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/num/mod.rs b/library/std/src/num/mod.rs index ffb8789c906ef..5aa6c1492ec65 100644 --- a/library/std/src/num/mod.rs +++ b/library/std/src/num/mod.rs @@ -6,6 +6,8 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#[unstable(feature = "complex_numbers", issue = "154023")] +pub use core::num::Complex; #[stable(feature = "int_error_matching", since = "1.55.0")] pub use core::num::IntErrorKind; #[stable(feature = "generic_nonzero", since = "1.79.0")] From 7b7f7f6fb2999292e37a96eb69b6e7cac18857c0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 6 Jul 2026 00:29:44 +0200 Subject: [PATCH 02/10] add `repr(complex)` --- compiler/rustc_abi/src/layout/ty.rs | 8 ++ compiler/rustc_abi/src/lib.rs | 7 ++ .../rustc_attr_parsing/src/attributes/repr.rs | 12 +++ compiler/rustc_feature/src/unstable.rs | 2 + .../rustc_hir/src/attrs/data_structures.rs | 1 + .../rustc_lint/src/types/improper_ctypes.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 4 + compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 8 +- compiler/rustc_span/src/symbol.rs | 2 + library/core/src/lib.rs | 1 + library/core/src/num/complex.rs | 2 +- ...attribute-on-wrong-item-inline-repr.stderr | 4 +- tests/ui/attributes/invalid-reprs.stderr | 2 +- .../feature-gate-repr-complex.rs | 30 ++++++ .../feature-gate-repr-complex.stderr | 97 +++++++++++++++++++ tests/ui/repr/invalid_repr_list_help.stderr | 10 +- 17 files changed, 182 insertions(+), 11 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-repr-complex.rs create mode 100644 tests/ui/feature-gates/feature-gate-repr-complex.stderr diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 9ca4aa2254547..cabc2436f4803 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -120,6 +120,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display { fn is_tuple(this: TyAndLayout<'a, Self>) -> bool; fn is_unit(this: TyAndLayout<'a, Self>) -> bool; fn is_transparent(this: TyAndLayout<'a, Self>) -> bool; + fn is_complex(this: TyAndLayout<'a, Self>) -> bool; fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool; /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool; @@ -220,6 +221,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } + pub fn is_complex(self) -> bool + where + Ty: TyAbiInterface<'a, C>, + { + Ty::is_complex(self) + } + pub fn is_scalable_vector(self) -> bool where Ty: TyAbiInterface<'a, C>, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index ad745913399d4..ea19d9a2cb8fe 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -95,10 +95,12 @@ bitflags! { /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5; const IS_SCALABLE = 1 << 6; + const IS_COMPLEX = 1 << 7; // Any of these flags being set prevent field reordering optimisation. const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() | ReprFlags::IS_SCALABLE.bits() + | ReprFlags::IS_COMPLEX.bits() | ReprFlags::IS_LINEAR.bits(); const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits(); } @@ -178,6 +180,11 @@ impl ReprOptions { self.flags.contains(ReprFlags::IS_C) } + #[inline] + pub fn complex(&self) -> bool { + self.flags.contains(ReprFlags::IS_COMPLEX) + } + #[inline] pub fn packed(&self) -> bool { self.pack.is_some() diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index dfb7ce5e7b2f4..4538c5c7c4a97 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -155,6 +155,17 @@ fn parse_repr(cx: &mut AcceptContext<'_, '_>, param: &MetaItemParser) -> Option< cx.expect_no_args(param.args())?; Some(ReprSimd) } + Some(sym::complex) => { + cx.check_target( + "(complex)", + &AllowedTargets::AllowList(&[ + Allow(Target::Struct), // Feature gated in `rustc_ast_passes` + Warn(Target::MacroCall), + ]), + ); + cx.expect_no_args(param.args())?; + Some(ReprComplex) + } Some(sym::transparent) => { cx.check_target( "(transparent)", @@ -190,6 +201,7 @@ fn parse_repr(cx: &mut AcceptContext<'_, '_>, param: &MetaItemParser) -> Option< sym::Rust, sym::C, sym::simd, + sym::complex, sym::transparent, sym::i8, sym::u8, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 01a4a7c499da0..9f5ff4adaa31e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -334,6 +334,8 @@ declare_features! ( (internal, panic_runtime, "1.10.0", Some(32837)), /// Allows using pattern types. (internal, pattern_types, "1.79.0", Some(123646)), + /// Allows `repr(complex)` for defining types that are ABI-compatible with C `_Complex`. + (internal, repr_complex, "CURRENT_RUSTC_VERSION", Some(154023)), /// Allows `repr(simd)` and importing the various simd intrinsics. (internal, repr_simd, "1.4.0", Some(27731)), /// Allows using compiler's own crates. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 29cfbe2558751..9e26e7f356d2d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -178,6 +178,7 @@ pub enum ReprAttr { ReprC, ReprPacked(Align), ReprSimd, + ReprComplex, ReprTransparent, ReprAlign(Align), } diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 0c34d9da66f1d..6793c270e32db 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -635,7 +635,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { debug_assert!(matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union)); use FfiResult::*; - if !def.repr().c() && !def.repr().transparent() { + if !def.repr().c() && !def.repr().transparent() && !def.repr().complex() { return FfiUnsafe { ty, reason: if def.is_struct() { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 1f3d4e32714a0..ccce1485cf68f 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1201,6 +1201,10 @@ where matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent()) } + fn is_complex(this: TyAndLayout<'tcx>) -> bool { + matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().complex()) + } + fn is_scalable_vector(this: TyAndLayout<'tcx>) -> bool { this.ty.is_scalable_vector() } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c482e6bb87345..1172cba6f471c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1600,6 +1600,7 @@ impl<'tcx> TyCtxt<'tcx> { } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprComplex => ReprFlags::IS_COMPLEX, attr::ReprInt(i) => { size = Some(match i { attr::IntType::SignedInt(x) => match x { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bf2dd237cd797..9bbcfb9d15eb5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1217,6 +1217,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut is_explicit_rust = false; let mut is_c = false; let mut is_simd = false; + let mut is_complex = false; let mut is_transparent = false; for (repr, _repr_span) in reprs { @@ -1232,6 +1233,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ReprAttr::ReprSimd => { is_simd = true; } + ReprAttr::ReprComplex => { + is_complex = true; + } ReprAttr::ReprTransparent => { is_transparent = true; } @@ -1264,19 +1268,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: target.to_string(), }); } - if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) { + if is_explicit_rust && (int_reprs > 0 || is_c || is_simd || is_complex) { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(diagnostics::ReprConflicting { hint_spans }); } // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) if (int_reprs > 1) || (is_simd && is_c) + || (is_complex && is_c) || (int_reprs == 1 && is_c && item.is_some_and(|item| { if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false } })) { + // FIXME: is_complex && is_c should be a hard error. self.tcx.emit_node_span_lint( CONFLICTING_REPR_HINTS, hir_id, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1d3f0adf86829..246c6f4cd722e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -651,6 +651,7 @@ symbols! { compiler_copy, compiler_fence, compiler_move, + complex, concat, concat_bytes, conservative_impl_trait, @@ -1702,6 +1703,7 @@ symbols! { repr128, repr_align, repr_align_enum, + repr_complex, repr_packed, repr_simd, repr_transparent, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2d7dd41ebac2f..25dbae6d3901b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -150,6 +150,7 @@ #![feature(pattern_types)] #![feature(pin_macro_internals)] #![feature(prelude_import)] +#![feature(repr_complex)] #![feature(repr_simd)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] diff --git a/library/core/src/num/complex.rs b/library/core/src/num/complex.rs index 4a4e4326f3902..d7feb760e2979 100644 --- a/library/core/src/num/complex.rs +++ b/library/core/src/num/complex.rs @@ -1,7 +1,7 @@ /// A complex number. #[derive(Clone, Copy, Debug, PartialEq)] #[unstable(feature = "complex_numbers", issue = "154023")] -#[repr(C)] +#[repr(complex)] pub struct Complex { /// The real component. pub re: T, diff --git a/tests/ui/attributes/attribute-on-wrong-item-inline-repr.stderr b/tests/ui/attributes/attribute-on-wrong-item-inline-repr.stderr index f9f17b1db10d7..8595c4d940719 100644 --- a/tests/ui/attributes/attribute-on-wrong-item-inline-repr.stderr +++ b/tests/ui/attributes/attribute-on-wrong-item-inline-repr.stderr @@ -41,7 +41,7 @@ error[E0539]: malformed `repr` attribute input LL | #[repr(nothing)] | ^^^^^^^-------^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit @@ -51,7 +51,7 @@ error[E0539]: malformed `repr` attribute input LL | #[repr(something_not_real)] | ^^^^^^^------------------^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit diff --git a/tests/ui/attributes/invalid-reprs.stderr b/tests/ui/attributes/invalid-reprs.stderr index 3cc52f552e1cc..a37902c71810b 100644 --- a/tests/ui/attributes/invalid-reprs.stderr +++ b/tests/ui/attributes/invalid-reprs.stderr @@ -25,7 +25,7 @@ error[E0539]: malformed `repr` attribute input LL | let y = #[repr(uwu(4))] | ^^^^^^^------^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit diff --git a/tests/ui/feature-gates/feature-gate-repr-complex.rs b/tests/ui/feature-gates/feature-gate-repr-complex.rs new file mode 100644 index 0000000000000..9f9073347ec57 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-complex.rs @@ -0,0 +1,30 @@ +#[repr(complex)] //~ ERROR: `repr(complex)` is experimental +struct Named { + a: u64, + b: u64, +} + +#[repr(complex)] //~ ERROR: `repr(complex)` is experimental +struct Unnamed(u64, u64); + +#[repr(C)] +//~^ ERROR conflicting representation hints +//~| WARN this was previously accepted +#[repr(complex)] //~ ERROR: `repr(complex)` is experimental +struct ConflictingRepr(u64, u64); + +#[repr(complex)] +//~^ ERROR: `repr(complex)` is experimental +//~| ERROR: attribute cannot be used on +union U { + f: u32, +} + +#[repr(complex)] +//~^ ERROR: `repr(complex)` is experimental +//~| error: attribute cannot be used on +enum E { + X, +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-repr-complex.stderr b/tests/ui/feature-gates/feature-gate-repr-complex.stderr new file mode 100644 index 0000000000000..c3298b64f0d9f --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-complex.stderr @@ -0,0 +1,97 @@ +error[E0658]: `repr(complex)` is experimental + --> $DIR/feature-gate-repr-complex.rs:1:1 + | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #154023 for more information + = help: add `#![feature(repr_complex)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `repr(complex)` is experimental + --> $DIR/feature-gate-repr-complex.rs:7:1 + | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #154023 for more information + = help: add `#![feature(repr_complex)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `repr(complex)` is experimental + --> $DIR/feature-gate-repr-complex.rs:13:1 + | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #154023 for more information + = help: add `#![feature(repr_complex)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `repr(complex)` is experimental + --> $DIR/feature-gate-repr-complex.rs:16:1 + | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #154023 for more information + = help: add `#![feature(repr_complex)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `repr(complex)` is experimental + --> $DIR/feature-gate-repr-complex.rs:23:1 + | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #154023 for more information + = help: add `#![feature(repr_complex)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `#[repr(complex)]` attribute cannot be used on unions + --> $DIR/feature-gate-repr-complex.rs:16:1 + | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = help: `#[repr(complex)]` can only be applied to structs + +error: `#[repr(complex)]` attribute cannot be used on enums + --> $DIR/feature-gate-repr-complex.rs:23:1 + | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = help: `#[repr(complex)]` can only be applied to structs + +error[E0566]: conflicting representation hints + --> $DIR/feature-gate-repr-complex.rs:10:8 + | +LL | #[repr(C)] + | ^ +... +LL | #[repr(complex)] + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0566, E0658. +For more information about an error, try `rustc --explain E0566`. +Future incompatibility report: Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/feature-gate-repr-complex.rs:10:8 + | +LL | #[repr(C)] + | ^ +... +LL | #[repr(complex)] + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` (part of `#[deny(future_incompatible)]`) on by default + diff --git a/tests/ui/repr/invalid_repr_list_help.stderr b/tests/ui/repr/invalid_repr_list_help.stderr index 82bf12f3f4dbc..b3fab97c5aad0 100644 --- a/tests/ui/repr/invalid_repr_list_help.stderr +++ b/tests/ui/repr/invalid_repr_list_help.stderr @@ -4,7 +4,7 @@ error[E0539]: malformed `repr` attribute input LL | #[repr(uwu)] | ^^^^^^^---^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit @@ -14,7 +14,7 @@ error[E0539]: malformed `repr` attribute input LL | #[repr(uwu = "a")] | ^^^^^^^---------^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit @@ -24,7 +24,7 @@ error[E0539]: malformed `repr` attribute input LL | #[repr(uwu(4))] | ^^^^^^^------^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit @@ -34,7 +34,7 @@ error[E0539]: malformed `repr` attribute input LL | #[repr(uwu, u8)] | ^^^^^^^---^^^^^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit @@ -44,7 +44,7 @@ error[E0539]: malformed `repr` attribute input LL | #[repr(uwu)] | ^^^^^^^---^^ | | - | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` + | valid arguments are `align`, `packed`, `Rust`, `C`, `simd`, `complex`, `transparent`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize` or `usize` | = note: for more information, visit From 047bd9c57fa74abc7b6e394582b7586fb7efe8e4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 7 Jul 2026 11:00:59 +0200 Subject: [PATCH 03/10] make `repr(complex)` an error on macro calls --- .../rustc_attr_parsing/src/attributes/repr.rs | 17 ++++++---- tests/ui/attributes/attr-on-mac-call.rs | 4 +++ tests/ui/attributes/attr-on-mac-call.stderr | 25 ++++++++++++-- .../feature-gate-repr-complex.stderr | 34 +++++++++---------- 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 4538c5c7c4a97..14b9b0c501f7c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -156,13 +156,16 @@ fn parse_repr(cx: &mut AcceptContext<'_, '_>, param: &MetaItemParser) -> Option< Some(ReprSimd) } Some(sym::complex) => { - cx.check_target( - "(complex)", - &AllowedTargets::AllowList(&[ - Allow(Target::Struct), // Feature gated in `rustc_ast_passes` - Warn(Target::MacroCall), - ]), - ); + if cx.features.is_some_and(|feats| !feats.repr_complex()) { + feature_err( + &cx.sess(), + sym::repr_complex, + param.span(), + "`repr(complex)` is experimental", + ) + .emit(); + } + cx.check_target("(complex)", &AllowedTargets::AllowList(&[Allow(Target::Struct)])); cx.expect_no_args(param.args())?; Some(ReprComplex) } diff --git a/tests/ui/attributes/attr-on-mac-call.rs b/tests/ui/attributes/attr-on-mac-call.rs index 7b30ec810ff81..487858e34a526 100644 --- a/tests/ui/attributes/attr-on-mac-call.rs +++ b/tests/ui/attributes/attr-on-mac-call.rs @@ -107,6 +107,10 @@ fn main() { //~^ ERROR attribute cannot be used on macro calls //~| ERROR SIMD types are experimental and possibly buggy unreachable!(); + #[repr(complex)] + //~^ ERROR attribute cannot be used on macro calls + //~| ERROR `repr(complex)` is experimental + unreachable!(); #[register_tool(xyz)] //~^ ERROR crate-level attribute should be an inner attribute unreachable!(); diff --git a/tests/ui/attributes/attr-on-mac-call.stderr b/tests/ui/attributes/attr-on-mac-call.stderr index 55d04165855d2..2537ad6388020 100644 --- a/tests/ui/attributes/attr-on-mac-call.stderr +++ b/tests/ui/attributes/attr-on-mac-call.stderr @@ -26,14 +26,33 @@ LL | #[repr(simd)] = help: `#[repr(simd)]` can only be applied to structs = note: placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute -error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![register_tool]` +error[E0658]: `repr(complex)` is experimental + --> $DIR/attr-on-mac-call.rs:110:12 + | +LL | #[repr(complex)] + | ^^^^^^^ + | + = note: see issue #154023 for more information + = help: add `#![feature(repr_complex)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `#[repr(complex)]` attribute cannot be used on macro calls --> $DIR/attr-on-mac-call.rs:110:5 | +LL | #[repr(complex)] + | ^^^^^^^^^^^^^^^^ + | + = help: `#[repr(complex)]` can only be applied to structs + = note: placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![register_tool]` + --> $DIR/attr-on-mac-call.rs:114:5 + | LL | #[register_tool(xyz)] | ^^^^^^^^^^^^^^^^^^^^^ | note: this attribute does not have an `!`, which means it is applied to this macro call - --> $DIR/attr-on-mac-call.rs:112:5 + --> $DIR/attr-on-mac-call.rs:116:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ @@ -341,6 +360,6 @@ LL | #[repr(Rust)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: placing this attribute on a macro invocation does nothing even if the macro expands to what would be a valid target for the attribute -error: aborting due to 4 previous errors; 30 warnings emitted +error: aborting due to 6 previous errors; 30 warnings emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-repr-complex.stderr b/tests/ui/feature-gates/feature-gate-repr-complex.stderr index c3298b64f0d9f..34baafd2120a2 100644 --- a/tests/ui/feature-gates/feature-gate-repr-complex.stderr +++ b/tests/ui/feature-gates/feature-gate-repr-complex.stderr @@ -1,60 +1,60 @@ error[E0658]: `repr(complex)` is experimental - --> $DIR/feature-gate-repr-complex.rs:1:1 + --> $DIR/feature-gate-repr-complex.rs:1:8 | LL | #[repr(complex)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: see issue #154023 for more information = help: add `#![feature(repr_complex)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `repr(complex)` is experimental - --> $DIR/feature-gate-repr-complex.rs:7:1 + --> $DIR/feature-gate-repr-complex.rs:7:8 | LL | #[repr(complex)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: see issue #154023 for more information = help: add `#![feature(repr_complex)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `repr(complex)` is experimental - --> $DIR/feature-gate-repr-complex.rs:13:1 + --> $DIR/feature-gate-repr-complex.rs:13:8 | LL | #[repr(complex)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: see issue #154023 for more information = help: add `#![feature(repr_complex)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `repr(complex)` is experimental - --> $DIR/feature-gate-repr-complex.rs:16:1 + --> $DIR/feature-gate-repr-complex.rs:16:8 | LL | #[repr(complex)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | = note: see issue #154023 for more information = help: add `#![feature(repr_complex)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0658]: `repr(complex)` is experimental - --> $DIR/feature-gate-repr-complex.rs:23:1 +error: `#[repr(complex)]` attribute cannot be used on unions + --> $DIR/feature-gate-repr-complex.rs:16:1 | LL | #[repr(complex)] | ^^^^^^^^^^^^^^^^ | - = note: see issue #154023 for more information - = help: add `#![feature(repr_complex)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: `#[repr(complex)]` can only be applied to structs -error: `#[repr(complex)]` attribute cannot be used on unions - --> $DIR/feature-gate-repr-complex.rs:16:1 +error[E0658]: `repr(complex)` is experimental + --> $DIR/feature-gate-repr-complex.rs:23:8 | LL | #[repr(complex)] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^ | - = help: `#[repr(complex)]` can only be applied to structs + = note: see issue #154023 for more information + = help: add `#![feature(repr_complex)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: `#[repr(complex)]` attribute cannot be used on enums --> $DIR/feature-gate-repr-complex.rs:23:1 From f3ece348bb86e79ed68cbd11c2279ed96d3ed231 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 7 Jul 2026 12:29:13 +0200 Subject: [PATCH 04/10] validate the struct `repr(complex)` is applied to --- .../rustc_hir_analysis/src/check/check.rs | 42 +++++++++++++++++++ tests/ui/repr/repr-complex-validation.rs | 29 +++++++++++++ tests/ui/repr/repr-complex-validation.stderr | 28 +++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 tests/ui/repr/repr-complex-validation.rs create mode 100644 tests/ui/repr/repr-complex-validation.stderr diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 574a2ad6d47f4..1c1e42be5e193 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -113,6 +113,8 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuarante check_scalable_vector(tcx, span, def_id, scalable); } else if def.repr().simd() { check_simd(tcx, span, def_id); + } else if def.repr().complex() { + check_complex(tcx, span, def_id); } check_transparent(tcx, def); @@ -1527,6 +1529,46 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { } } +fn check_complex(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { + let t = tcx.type_of(def_id).instantiate_identity().skip_norm_wip(); + let ty::Adt(def, args) = t.kind() else { return }; + + // This constraint is enforced during attribute parsing. + assert!(def.is_struct(), "`repr(complex)` is only allowed on structs"); + + let fields = &def.non_enum_variant().fields; + + // A complex number is a pair, so we require exactly two fields of the same type. + let (Some(first), Some(second)) = (fields.get(FieldIdx::ZERO), fields.get(FieldIdx::ONE)) + else { + tcx.dcx().struct_span_err(sp, "`repr(complex)` type must have two fields").emit(); + return; + }; + + if let Some(third) = fields.get(FieldIdx::from_usize(2)) { + tcx.dcx() + .struct_span_err(sp, "`repr(complex)` type cannot have more than two fields") + .with_span_label(tcx.def_span(third.did), "excess field") + .emit(); + return; + } + + // repr(complex) is internal, so this check is not as thorough as we'd require if it were + // user-facing. + let first_ty = first.ty(tcx, args).skip_norm_wip(); + let second_ty = second.ty(tcx, args).skip_norm_wip(); + if first_ty != second_ty { + tcx.dcx() + .struct_span_err(sp, "`repr(complex)` type must have two fields of the same type") + .with_span_label(tcx.def_span(first.did), format!("this field is of type `{first_ty}`")) + .with_span_label( + tcx.def_span(second.did), + format!("this field is of type `{second_ty}`"), + ) + .emit(); + } +} + #[tracing::instrument(skip(tcx), level = "debug")] fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) { let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip(); diff --git a/tests/ui/repr/repr-complex-validation.rs b/tests/ui/repr/repr-complex-validation.rs new file mode 100644 index 0000000000000..5b7c626a29aed --- /dev/null +++ b/tests/ui/repr/repr-complex-validation.rs @@ -0,0 +1,29 @@ +// Check that `#[repr(complex)]` validates the shape of the type it is applied to: +// it must be a struct with exactly two fields of the same type. +#![feature(repr_complex)] +#![crate_type = "lib"] + +#[repr(complex)] +struct Zero; //~ ERROR `repr(complex)` type must have two fields + +#[repr(complex)] +struct One(f32); //~ ERROR `repr(complex)` type must have two fields + +#[repr(complex)] +struct Three(f32, f32, f32); //~ ERROR `repr(complex)` type cannot have more than two fields + +#[repr(complex)] +struct DifferentTypes(f32, f64); //~ ERROR `repr(complex)` type must have two fields of the same type + +// These are well-formed. +#[repr(complex)] +struct GoodTuple(f32, f32); + +#[repr(complex)] +struct GoodNamed { + re: f64, + im: f64, +} + +#[repr(complex)] +struct GoodGeneric(T, T); diff --git a/tests/ui/repr/repr-complex-validation.stderr b/tests/ui/repr/repr-complex-validation.stderr new file mode 100644 index 0000000000000..bcf9d1605af95 --- /dev/null +++ b/tests/ui/repr/repr-complex-validation.stderr @@ -0,0 +1,28 @@ +error: `repr(complex)` type must have two fields + --> $DIR/repr-complex-validation.rs:7:1 + | +LL | struct Zero; + | ^^^^^^^^^^^ + +error: `repr(complex)` type must have two fields + --> $DIR/repr-complex-validation.rs:10:1 + | +LL | struct One(f32); + | ^^^^^^^^^^ + +error: `repr(complex)` type cannot have more than two fields + --> $DIR/repr-complex-validation.rs:13:1 + | +LL | struct Three(f32, f32, f32); + | ^^^^^^^^^^^^ --- excess field + +error: `repr(complex)` type must have two fields of the same type + --> $DIR/repr-complex-validation.rs:16:1 + | +LL | struct DifferentTypes(f32, f64); + | ^^^^^^^^^^^^^^^^^^^^^ --- --- this field is of type `f64` + | | + | this field is of type `f32` + +error: aborting due to 4 previous errors + From 00b6500e3f9987134ffac8dc769bb63d24caed55 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 7 Jul 2026 13:47:32 +0200 Subject: [PATCH 05/10] make improper_ctypes only accept `Complex<{float}>` --- .../rustc_lint/src/types/improper_ctypes.rs | 32 +++++++++++++ tests/ui/lint/improper-ctypes/repr-complex.rs | 48 +++++++++++++++++++ .../lint/improper-ctypes/repr-complex.stderr | 35 ++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 tests/ui/lint/improper-ctypes/repr-complex.rs create mode 100644 tests/ui/lint/improper-ctypes/repr-complex.stderr diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 6793c270e32db..1b7d253b85613 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -656,6 +656,38 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } + // We only guarantee that Complex<{float}> is C-compatible for now. + if def.repr().complex() + && let Some(field) = def.non_enum_variant().fields.iter().next() + { + let mut field_ty = + maybe_normalize_erasing_regions(self.cx, field.ty(self.cx.tcx, args)); + + // Peel off any transparent wrappers. + while let ty::Adt(inner, inner_args) = field_ty.kind() + && inner.repr().transparent() + && let Some(inner_field) = + super::transparent_newtype_field(self.cx.tcx, inner.non_enum_variant()) + { + field_ty = maybe_normalize_erasing_regions( + self.cx, + inner_field.ty(self.cx.tcx, inner_args), + ); + } + + if !field_ty.is_floating_point() { + return FfiUnsafe { + ty, + reason: msg!( + "this `repr(complex)` struct only has a C-compatible layout with floating-point fields" + ), + help: Some(msg!( + "only `repr(complex)` structs whose fields are `f16`, `f32`, `f64`, or `f128` have a C-compatible layout" + )), + }; + } + } + if def.non_enum_variant().field_list_has_applicable_non_exhaustive() { return FfiUnsafe { ty, diff --git a/tests/ui/lint/improper-ctypes/repr-complex.rs b/tests/ui/lint/improper-ctypes/repr-complex.rs new file mode 100644 index 0000000000000..84e0bec7e8a30 --- /dev/null +++ b/tests/ui/lint/improper-ctypes/repr-complex.rs @@ -0,0 +1,48 @@ +// Currently we only guarantee that repr(complex) on a Complex<{float}> is ABI-compatible. +#![feature(repr_complex)] +#![feature(f16, f128)] +#![deny(improper_ctypes)] +#![crate_type = "lib"] + +#[repr(complex)] +pub struct ComplexF16(f16, f16); + +#[repr(complex)] +pub struct ComplexF32(f32, f32); + +#[repr(complex)] +pub struct ComplexF64(f64, f64); + +#[repr(complex)] +pub struct ComplexF128(f128, f128); + +#[repr(transparent)] +pub struct Wrap(f32); + +#[repr(complex)] +pub struct ComplexWrap(Wrap, Wrap); + +#[repr(transparent)] +pub struct WrapWrap(Wrap); + +#[repr(complex)] +pub struct ComplexWrapWrap(WrapWrap, WrapWrap); + +#[repr(complex)] +pub struct ComplexI32(i32, i32); + +#[repr(complex)] +pub struct ComplexU64(u64, u64); + +extern "C" { + pub fn complex_f16(x: ComplexF16); + pub fn complex_f32(x: ComplexF32); + pub fn complex_f64(x: ComplexF64); + pub fn complex_f128(x: ComplexF128); + + pub fn complex_wrap(x: ComplexWrap); + pub fn complex_wrap_wrap(x: ComplexWrapWrap); + + pub fn complex_i32(x: ComplexI32); //~ ERROR `extern` block uses type `ComplexI32` + pub fn complex_u64(x: ComplexU64); //~ ERROR `extern` block uses type `ComplexU64` +} diff --git a/tests/ui/lint/improper-ctypes/repr-complex.stderr b/tests/ui/lint/improper-ctypes/repr-complex.stderr new file mode 100644 index 0000000000000..8b8bc4202e2e3 --- /dev/null +++ b/tests/ui/lint/improper-ctypes/repr-complex.stderr @@ -0,0 +1,35 @@ +error: `extern` block uses type `ComplexI32`, which is not FFI-safe + --> $DIR/repr-complex.rs:46:27 + | +LL | pub fn complex_i32(x: ComplexI32); + | ^^^^^^^^^^ not FFI-safe + | + = help: only `repr(complex)` structs whose fields are `f16`, `f32`, `f64`, or `f128` have a C-compatible layout + = note: this `repr(complex)` struct only has a C-compatible layout with floating-point fields +note: the type is defined here + --> $DIR/repr-complex.rs:32:1 + | +LL | pub struct ComplexI32(i32, i32); + | ^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/repr-complex.rs:4:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: `extern` block uses type `ComplexU64`, which is not FFI-safe + --> $DIR/repr-complex.rs:47:27 + | +LL | pub fn complex_u64(x: ComplexU64); + | ^^^^^^^^^^ not FFI-safe + | + = help: only `repr(complex)` structs whose fields are `f16`, `f32`, `f64`, or `f128` have a C-compatible layout + = note: this `repr(complex)` struct only has a C-compatible layout with floating-point fields +note: the type is defined here + --> $DIR/repr-complex.rs:35:1 + | +LL | pub struct ComplexU64(u64, u64); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From bd321649edb348353fe5ed855491bf7f0d7522e5 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 6 Jul 2026 22:50:54 +0200 Subject: [PATCH 06/10] add `Complex` to `minicore.rs` --- tests/auxiliary/minicore.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index d63d48e56903d..4dfa7aa0fd07f 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -31,6 +31,7 @@ f16, f128, transparent_unions, + repr_complex, asm_experimental_arch, unboxed_closures )] @@ -390,6 +391,18 @@ pub mod hint { } } +pub mod num { + use super::Copy; + + #[repr(complex)] + pub struct Complex { + pub re: T, + pub im: T, + } + + impl Copy for Complex {} +} + #[lang = "c_void"] #[repr(u8)] pub enum c_void { From 9f87e3b2bbc00001a14fc5cdd0b830f2bd6c4578 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 6 Jul 2026 22:55:47 +0200 Subject: [PATCH 07/10] add `complex-abi.rs` test --- tests/codegen-llvm/complex-abi.rs | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/codegen-llvm/complex-abi.rs diff --git a/tests/codegen-llvm/complex-abi.rs b/tests/codegen-llvm/complex-abi.rs new file mode 100644 index 0000000000000..2f0a6a344a9e6 --- /dev/null +++ b/tests/codegen-llvm/complex-abi.rs @@ -0,0 +1,55 @@ +//! Checks that `#[repr(complex)]` `Complex` matches the C `_Complex` ABI in `extern "C"` +//! functions. This is the rustc side of `tests/run-make/complex-c-abi`, which additionally +//! checks these signatures against clang. Revisions are grouped by LLVM component. + +//@ add-minicore +//@ compile-flags: -C no-prepopulate-passes -Z codegen-source-order + +#![feature(no_core, lang_items, repr_complex, f16, f128)] +#![no_core] +#![allow(improper_ctypes)] // only Complex<{float}> is guaranteed to be ABI-compatible for now +#![crate_type = "lib"] + +extern crate minicore; +use minicore::num::Complex; + +#[no_mangle] +pub extern "C" fn cplx_f16(x: Complex) -> Complex { + // CHECK: cplx_f16 + x +} + +#[no_mangle] +pub extern "C" fn cplx_f32(x: Complex) -> Complex { + x +} + +#[no_mangle] +pub extern "C" fn cplx_f64(x: Complex) -> Complex { + x +} + +#[no_mangle] +pub extern "C" fn cplx_f128(x: Complex) -> Complex { + x +} + +#[no_mangle] +pub extern "C" fn cplx_i8(x: Complex) -> Complex { + x +} + +#[no_mangle] +pub extern "C" fn cplx_i16(x: Complex) -> Complex { + x +} + +#[no_mangle] +pub extern "C" fn cplx_i32(x: Complex) -> Complex { + x +} + +#[no_mangle] +pub extern "C" fn cplx_i64(x: Complex) -> Complex { + x +} From 5cf9142ce4b107c2c85a6f8443a61874d7046fe8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 6 Jul 2026 23:21:20 +0200 Subject: [PATCH 08/10] add CHECK lines and revisions --- tests/codegen-llvm/complex-abi.rs | 282 +++++++++++++++++++++++++++++- 1 file changed, 281 insertions(+), 1 deletion(-) diff --git a/tests/codegen-llvm/complex-abi.rs b/tests/codegen-llvm/complex-abi.rs index 2f0a6a344a9e6..6c0a26170043f 100644 --- a/tests/codegen-llvm/complex-abi.rs +++ b/tests/codegen-llvm/complex-abi.rs @@ -5,6 +5,90 @@ //@ add-minicore //@ compile-flags: -C no-prepopulate-passes -Z codegen-source-order +//@ revisions: X86_64 I686 WINDOWS_MSVC WINDOWS_GNU WIN32_MSVC WIN32_GNU +//@ [X86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@ [X86_64] needs-llvm-components: x86 +//@ [I686] compile-flags: --target i686-unknown-linux-gnu +//@ [I686] needs-llvm-components: x86 +//@ [WINDOWS_MSVC] compile-flags: --target x86_64-pc-windows-msvc +//@ [WINDOWS_MSVC] needs-llvm-components: x86 +//@ [WINDOWS_GNU] compile-flags: --target x86_64-pc-windows-gnu +//@ [WINDOWS_GNU] needs-llvm-components: x86 +//@ [WIN32_MSVC] compile-flags: --target i686-pc-windows-msvc +//@ [WIN32_MSVC] needs-llvm-components: x86 +//@ [WIN32_GNU] compile-flags: --target i686-pc-windows-gnu +//@ [WIN32_GNU] needs-llvm-components: x86 + +//@ revisions: AARCH64 AARCH64_DARWIN AARCH64_MSVC ARM64EC +//@ [AARCH64] compile-flags: --target aarch64-unknown-linux-gnu +//@ [AARCH64] needs-llvm-components: aarch64 +//@ [AARCH64_DARWIN] compile-flags: --target aarch64-apple-darwin +//@ [AARCH64_DARWIN] needs-llvm-components: aarch64 +//@ [AARCH64_MSVC] compile-flags: --target aarch64-pc-windows-msvc +//@ [AARCH64_MSVC] needs-llvm-components: aarch64 +//@ [ARM64EC] compile-flags: --target arm64ec-pc-windows-msvc +//@ [ARM64EC] needs-llvm-components: aarch64 + +//@ revisions: ARM +//@ [ARM] compile-flags: --target arm-unknown-linux-gnueabihf +//@ [ARM] needs-llvm-components: arm + +//@ revisions: RISCV64 RISCV32 +//@ [RISCV64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [RISCV64] needs-llvm-components: riscv +//@ [RISCV32] compile-flags: --target riscv32gc-unknown-linux-gnu +//@ [RISCV32] needs-llvm-components: riscv + +//@ revisions: LOONGARCH64 LOONGARCH32 +//@ [LOONGARCH64] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [LOONGARCH64] needs-llvm-components: loongarch +//@ [LOONGARCH32] compile-flags: --target loongarch32-unknown-none +//@ [LOONGARCH32] needs-llvm-components: loongarch + +//@ revisions: SPARC64 SPARC +//@ [SPARC64] compile-flags: --target sparc64-unknown-linux-gnu +//@ [SPARC64] needs-llvm-components: sparc +//@ [SPARC] compile-flags: --target sparc-unknown-linux-gnu +//@ [SPARC] needs-llvm-components: sparc + +//@ revisions: S390X +//@ [S390X] compile-flags: --target s390x-unknown-linux-gnu +//@ [S390X] needs-llvm-components: systemz + +//@ revisions: POWERPC POWERPC64LE POWERPC64 AIX +//@ [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu +//@ [POWERPC] needs-llvm-components: powerpc +//@ [POWERPC64LE] compile-flags: --target powerpc64le-unknown-linux-gnu +//@ [POWERPC64LE] needs-llvm-components: powerpc +//@ [POWERPC64] compile-flags: --target powerpc64-unknown-linux-gnu +//@ [POWERPC64] needs-llvm-components: powerpc +//@ [AIX] compile-flags: --target powerpc64-ibm-aix +//@ [AIX] needs-llvm-components: powerpc + +//@ revisions: MIPS64EL MIPS +//@ [MIPS64EL] compile-flags: --target mips64el-unknown-linux-gnuabi64 +//@ [MIPS64EL] needs-llvm-components: mips +//@ [MIPS] compile-flags: --target mips-unknown-linux-gnu +//@ [MIPS] needs-llvm-components: mips + +//@ revisions: WASM32 WASM64 +//@ [WASM32] compile-flags: --target wasm32-unknown-unknown +//@ [WASM32] needs-llvm-components: webassembly +//@ [WASM64] compile-flags: --target wasm64-unknown-unknown +//@ [WASM64] needs-llvm-components: webassembly + +//@ revisions: CSKY +//@ [CSKY] compile-flags: --target csky-unknown-linux-gnuabiv2 +//@ [CSKY] needs-llvm-components: csky + +//@ revisions: NVPTX +//@ [NVPTX] compile-flags: --target nvptx64-nvidia-cuda +//@ [NVPTX] needs-llvm-components: nvptx + +//@ revisions: BPF +//@ [BPF] compile-flags: --target bpfel-unknown-none +//@ [BPF] needs-llvm-components: bpf + #![feature(no_core, lang_items, repr_complex, f16, f128)] #![no_core] #![allow(improper_ctypes)] // only Complex<{float}> is guaranteed to be ABI-compatible for now @@ -15,41 +99,237 @@ use minicore::num::Complex; #[no_mangle] pub extern "C" fn cplx_f16(x: Complex) -> Complex { - // CHECK: cplx_f16 + // AARCH64: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) + // AARCH64_DARWIN: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) + // AARCH64_MSVC: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) + // ARM64EC: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) + // ARM: define{{.*}} i32 @cplx_f16([1 x i32] {{.*}}) + // I686: define{{.*}} <2 x half> @cplx_f16(ptr {{.*}} byval({ half, half }) {{.*}}) + // LOONGARCH32: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) + // LOONGARCH64: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) + // NVPTX: define{{.*}} { half, half } @cplx_f16(ptr {{.*}} byval({ half, half }) {{.*}}) + // RISCV32: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) + // RISCV64: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) + // S390X: define{{.*}} void @cplx_f16(ptr {{.*}} sret({ half, half }) {{.*}}, ptr {{.*}}) + // WIN32_GNU: define{{.*}} <2 x half> @cplx_f16(ptr {{.*}} byval({ half, half }) {{.*}}) + // WIN32_MSVC: define{{.*}} <2 x half> @cplx_f16(ptr {{.*}} byval({ half, half }) {{.*}}) + // WINDOWS_GNU: define{{.*}} i32 @cplx_f16(i32 {{.*}}) + // WINDOWS_MSVC: define{{.*}} i32 @cplx_f16(i32 {{.*}}) + // X86_64: define{{.*}} <2 x half> @cplx_f16(<2 x half> {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_f32(x: Complex) -> Complex { + // AARCH64: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) + // AARCH64_DARWIN: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) + // AARCH64_MSVC: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) + // AIX: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // ARM64EC: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) + // ARM: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) + // BPF: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, i64 {{.*}}) + // CSKY: define{{.*}} [2 x i32] @cplx_f32([2 x i32] {{.*}}) + // I686: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) + // LOONGARCH32: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // LOONGARCH64: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // MIPS64EL: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // MIPS: define{{.*}} { float, float } @cplx_f32(i32 {{.*}}, i32 {{.*}}) + // NVPTX: define{{.*}} { float, float } @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) + // POWERPC64: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // POWERPC64LE: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // POWERPC: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}} byval({ float, float }) {{.*}}) + // RISCV32: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // RISCV64: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // S390X: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}}) + // SPARC64: define{{.*}} {{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // SPARC: define{{.*}} { float, float } @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) + // WASM32: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}} byval({ float, float }) {{.*}}) + // WASM64: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}} byval({ float, float }) {{.*}}) + // WIN32_GNU: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) + // WIN32_MSVC: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) + // WINDOWS_GNU: define{{.*}} i64 @cplx_f32(i64 {{.*}}) + // WINDOWS_MSVC: define{{.*}} i64 @cplx_f32(i64 {{.*}}) + // X86_64: define{{.*}} <2 x float> @cplx_f32(<2 x float> {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_f64(x: Complex) -> Complex { + // AARCH64: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) + // AARCH64_DARWIN: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) + // AARCH64_MSVC: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) + // AIX: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // ARM64EC: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) + // ARM: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) + // BPF: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, [2 x i64] {{.*}}) + // CSKY: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, [4 x i32] {{.*}}) + // I686: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) + // LOONGARCH32: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // LOONGARCH64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // MIPS64EL: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // MIPS: define{{.*}} { double, double } @cplx_f64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) + // NVPTX: define{{.*}} { double, double } @cplx_f64(ptr {{.*}} byval({ double, double }) {{.*}}) + // POWERPC64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // POWERPC64LE: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // POWERPC: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) + // RISCV32: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // RISCV64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // S390X: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}}) + // SPARC64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // SPARC: define{{.*}} { double, double } @cplx_f64(ptr {{.*}} byval({ double, double }) {{.*}}) + // WASM32: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) + // WASM64: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) + // WIN32_GNU: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) + // WIN32_MSVC: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) + // WINDOWS_GNU: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}}) + // WINDOWS_MSVC: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}}) + // X86_64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_f128(x: Complex) -> Complex { + // I686: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) + // WASM64: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) + // WIN32_GNU: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) + // WINDOWS_GNU: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}}) + // X86_64: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_i8(x: Complex) -> Complex { + // AARCH64: define{{.*}} i16 @cplx_i8(i64{{.*}}) + // AARCH64_DARWIN: define{{.*}} i16 @cplx_i8(i64{{.*}}) + // AARCH64_MSVC: define{{.*}} i16 @cplx_i8(i64{{.*}}) + // AIX: define{{.*}} { i8, i8 } @cplx_i8(i8 {{.*}}, i8 {{.*}}) + // ARM64EC: define{{.*}} i16 @cplx_i8(i64{{.*}}) + // ARM: define{{.*}} i16 @cplx_i8([1 x i32]{{.*}}) + // BPF: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, i16 {{.*}}) + // CSKY: define{{.*}} {{.*}} i32 @cplx_i8(i32{{.*}}) + // I686: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // LOONGARCH32: define{{.*}} {{.*}} i32 @cplx_i8(i32{{.*}}) + // LOONGARCH64: define{{.*}} {{.*}} i64 @cplx_i8(i64{{.*}}) + // MIPS64EL: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) + // MIPS: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) + // NVPTX: define{{.*}} { i8, i8 } @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // POWERPC64: define{{.*}} { i8, i8 } @cplx_i8(i8 {{.*}}, i8 {{.*}}) + // POWERPC64LE: define{{.*}} { i8, i8 } @cplx_i8(i8 {{.*}}, i8 {{.*}}) + // POWERPC: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // RISCV32: define{{.*}} {{.*}} i32 @cplx_i8(i32{{.*}}) + // RISCV64: define{{.*}} {{.*}} i64 @cplx_i8(i64{{.*}}) + // S390X: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}}) + // SPARC64: define{{.*}} {{.*}} i64 @cplx_i8(i64{{.*}}) + // SPARC: define{{.*}} { i8, i8 } @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // WASM64: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // WIN32_GNU: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // WIN32_MSVC: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // WINDOWS_GNU: define{{.*}} i16 @cplx_i8(i16 {{.*}}) + // WINDOWS_MSVC: define{{.*}} i16 @cplx_i8(i16 {{.*}}) + // X86_64: define{{.*}} i16 @cplx_i8(i16 {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_i16(x: Complex) -> Complex { + // AARCH64: define{{.*}} i32 @cplx_i16(i64{{.*}}) + // AARCH64_DARWIN: define{{.*}} i32 @cplx_i16(i64{{.*}}) + // AARCH64_MSVC: define{{.*}} i32 @cplx_i16(i64{{.*}}) + // AIX: define{{.*}} { i16, i16 } @cplx_i16(i16 {{.*}}, i16 {{.*}}) + // ARM64EC: define{{.*}} i32 @cplx_i16(i64{{.*}}) + // ARM: define{{.*}} i32 @cplx_i16([1 x i32] {{.*}}) + // BPF: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, i32 {{.*}}) + // CSKY: define{{.*}} i32 @cplx_i16(i32 {{.*}}) + // I686: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // LOONGARCH32: define{{.*}} i32 @cplx_i16(i32 {{.*}}) + // LOONGARCH64: define{{.*}} {{.*}} i64 @cplx_i16(i64{{.*}}) + // MIPS64EL: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) + // MIPS: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) + // NVPTX: define{{.*}} { i16, i16 } @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // POWERPC64: define{{.*}} { i16, i16 } @cplx_i16(i16 {{.*}}, i16 {{.*}}) + // POWERPC64LE: define{{.*}} { i16, i16 } @cplx_i16(i16 {{.*}}, i16 {{.*}}) + // POWERPC: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // RISCV32: define{{.*}} i32 @cplx_i16(i32 {{.*}}) + // RISCV64: define{{.*}} {{.*}} i64 @cplx_i16(i64{{.*}}) + // S390X: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}}) + // SPARC64: define{{.*}} {{.*}} i64 @cplx_i16(i64{{.*}}) + // SPARC: define{{.*}} { i16, i16 } @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // WASM64: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // WIN32_GNU: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // WIN32_MSVC: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // WINDOWS_GNU: define{{.*}} i32 @cplx_i16(i32 {{.*}}) + // WINDOWS_MSVC: define{{.*}} i32 @cplx_i16(i32 {{.*}}) + // X86_64: define{{.*}} i32 @cplx_i16(i32 {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_i32(x: Complex) -> Complex { + // AARCH64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // AARCH64_DARWIN: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // AARCH64_MSVC: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // AIX: define{{.*}} { i32, i32 } @cplx_i32(i32 {{.*}}, i32 {{.*}}) + // ARM64EC: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // ARM: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, [2 x i32] {{.*}}) + // BPF: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, i64 {{.*}}) + // CSKY: define{{.*}} [2 x i32] @cplx_i32([2 x i32] {{.*}}) + // I686: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // LOONGARCH32: define{{.*}} [2 x i32] @cplx_i32([2 x i32] {{.*}}) + // LOONGARCH64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // MIPS64EL: define{{.*}} { i32, i32 } @cplx_i32(i64 {{.*}}) + // MIPS: define{{.*}} { i32, i32 } @cplx_i32(i32 {{.*}}, i32 {{.*}}) + // NVPTX: define{{.*}} { i32, i32 } @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // POWERPC64: define{{.*}} { i32, i32 } @cplx_i32(i32 {{.*}}, i32 {{.*}}) + // POWERPC64LE: define{{.*}} { i32, i32 } @cplx_i32(i32 {{.*}}, i32 {{.*}}) + // POWERPC: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // RISCV32: define{{.*}} [2 x i32] @cplx_i32([2 x i32] {{.*}}) + // RISCV64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // S390X: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}}) + // SPARC64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // SPARC: define{{.*}} { i32, i32 } @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // WASM64: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // WIN32_GNU: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // WIN32_MSVC: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // WINDOWS_GNU: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // WINDOWS_MSVC: define{{.*}} i64 @cplx_i32(i64 {{.*}}) + // X86_64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_i64(x: Complex) -> Complex { + // AARCH64: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) + // AARCH64_DARWIN: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) + // AARCH64_MSVC: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) + // AIX: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // ARM64EC: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) + // ARM: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [2 x i64] {{.*}}) + // BPF: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [2 x i64] {{.*}}) + // CSKY: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [4 x i32] {{.*}}) + // I686: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // LOONGARCH32: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // LOONGARCH64: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) + // MIPS64EL: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // MIPS: define{{.*}} { i64, i64 } @cplx_i64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) + // NVPTX: define{{.*}} { i64, i64 } @cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // POWERPC64: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // POWERPC64LE: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // POWERPC: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // RISCV32: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // RISCV64: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) + // S390X: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // SPARC64: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // SPARC: define{{.*}} { i64, i64 } @cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // WASM64: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // WIN32_GNU: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // WIN32_MSVC: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // WINDOWS_GNU: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // WINDOWS_MSVC: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // X86_64: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) x } From a9586bb016b33a46520b2b3b8116508f873a1edd Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 6 Jul 2026 23:25:14 +0200 Subject: [PATCH 09/10] disable most revisions --- tests/codegen-llvm/complex-abi.rs | 134 +++++++++++++++--------------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/tests/codegen-llvm/complex-abi.rs b/tests/codegen-llvm/complex-abi.rs index 6c0a26170043f..9d79cb0889fd4 100644 --- a/tests/codegen-llvm/complex-abi.rs +++ b/tests/codegen-llvm/complex-abi.rs @@ -5,89 +5,93 @@ //@ add-minicore //@ compile-flags: -C no-prepopulate-passes -Z codegen-source-order -//@ revisions: X86_64 I686 WINDOWS_MSVC WINDOWS_GNU WIN32_MSVC WIN32_GNU +//@ revisions: X86_64 WINDOWS_MSVC WINDOWS_GNU //@ [X86_64] compile-flags: --target x86_64-unknown-linux-gnu //@ [X86_64] needs-llvm-components: x86 -//@ [I686] compile-flags: --target i686-unknown-linux-gnu -//@ [I686] needs-llvm-components: x86 //@ [WINDOWS_MSVC] compile-flags: --target x86_64-pc-windows-msvc //@ [WINDOWS_MSVC] needs-llvm-components: x86 //@ [WINDOWS_GNU] compile-flags: --target x86_64-pc-windows-gnu //@ [WINDOWS_GNU] needs-llvm-components: x86 -//@ [WIN32_MSVC] compile-flags: --target i686-pc-windows-msvc -//@ [WIN32_MSVC] needs-llvm-components: x86 -//@ [WIN32_GNU] compile-flags: --target i686-pc-windows-gnu -//@ [WIN32_GNU] needs-llvm-components: x86 -//@ revisions: AARCH64 AARCH64_DARWIN AARCH64_MSVC ARM64EC -//@ [AARCH64] compile-flags: --target aarch64-unknown-linux-gnu -//@ [AARCH64] needs-llvm-components: aarch64 -//@ [AARCH64_DARWIN] compile-flags: --target aarch64-apple-darwin -//@ [AARCH64_DARWIN] needs-llvm-components: aarch64 -//@ [AARCH64_MSVC] compile-flags: --target aarch64-pc-windows-msvc -//@ [AARCH64_MSVC] needs-llvm-components: aarch64 -//@ [ARM64EC] compile-flags: --target arm64ec-pc-windows-msvc -//@ [ARM64EC] needs-llvm-components: aarch64 +// FIXME: the below revisions are deliberately disabled for now. -//@ revisions: ARM -//@ [ARM] compile-flags: --target arm-unknown-linux-gnueabihf -//@ [ARM] needs-llvm-components: arm +// revisions: I686 WIN32_MSVC WIN32_GNU +// [I686] compile-flags: --target i686-unknown-linux-gnu +// [I686] needs-llvm-components: x86 +// [WIN32_MSVC] compile-flags: --target i686-pc-windows-msvc +// [WIN32_MSVC] needs-llvm-components: x86 +// [WIN32_GNU] compile-flags: --target i686-pc-windows-gnu +// [WIN32_GNU] needs-llvm-components: x86 -//@ revisions: RISCV64 RISCV32 -//@ [RISCV64] compile-flags: --target riscv64gc-unknown-linux-gnu -//@ [RISCV64] needs-llvm-components: riscv -//@ [RISCV32] compile-flags: --target riscv32gc-unknown-linux-gnu -//@ [RISCV32] needs-llvm-components: riscv +// revisions: AARCH64 AARCH64_DARWIN AARCH64_MSVC ARM64EC +// [AARCH64] compile-flags: --target aarch64-unknown-linux-gnu +// [AARCH64] needs-llvm-components: aarch64 +// [AARCH64_DARWIN] compile-flags: --target aarch64-apple-darwin +// [AARCH64_DARWIN] needs-llvm-components: aarch64 +// [AARCH64_MSVC] compile-flags: --target aarch64-pc-windows-msvc +// [AARCH64_MSVC] needs-llvm-components: aarch64 +// [ARM64EC] compile-flags: --target arm64ec-pc-windows-msvc +// [ARM64EC] needs-llvm-components: aarch64 -//@ revisions: LOONGARCH64 LOONGARCH32 -//@ [LOONGARCH64] compile-flags: --target loongarch64-unknown-linux-gnu -//@ [LOONGARCH64] needs-llvm-components: loongarch -//@ [LOONGARCH32] compile-flags: --target loongarch32-unknown-none -//@ [LOONGARCH32] needs-llvm-components: loongarch +// revisions: ARM +// [ARM] compile-flags: --target arm-unknown-linux-gnueabihf +// [ARM] needs-llvm-components: arm -//@ revisions: SPARC64 SPARC -//@ [SPARC64] compile-flags: --target sparc64-unknown-linux-gnu -//@ [SPARC64] needs-llvm-components: sparc -//@ [SPARC] compile-flags: --target sparc-unknown-linux-gnu -//@ [SPARC] needs-llvm-components: sparc +// revisions: RISCV64 RISCV32 +// [RISCV64] compile-flags: --target riscv64gc-unknown-linux-gnu +// [RISCV64] needs-llvm-components: riscv +// [RISCV32] compile-flags: --target riscv32gc-unknown-linux-gnu +// [RISCV32] needs-llvm-components: riscv -//@ revisions: S390X -//@ [S390X] compile-flags: --target s390x-unknown-linux-gnu -//@ [S390X] needs-llvm-components: systemz +// revisions: LOONGARCH64 LOONGARCH32 +// [LOONGARCH64] compile-flags: --target loongarch64-unknown-linux-gnu +// [LOONGARCH64] needs-llvm-components: loongarch +// [LOONGARCH32] compile-flags: --target loongarch32-unknown-none +// [LOONGARCH32] needs-llvm-components: loongarch -//@ revisions: POWERPC POWERPC64LE POWERPC64 AIX -//@ [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu -//@ [POWERPC] needs-llvm-components: powerpc -//@ [POWERPC64LE] compile-flags: --target powerpc64le-unknown-linux-gnu -//@ [POWERPC64LE] needs-llvm-components: powerpc -//@ [POWERPC64] compile-flags: --target powerpc64-unknown-linux-gnu -//@ [POWERPC64] needs-llvm-components: powerpc -//@ [AIX] compile-flags: --target powerpc64-ibm-aix -//@ [AIX] needs-llvm-components: powerpc +// revisions: SPARC64 SPARC +// [SPARC64] compile-flags: --target sparc64-unknown-linux-gnu +// [SPARC64] needs-llvm-components: sparc +// [SPARC] compile-flags: --target sparc-unknown-linux-gnu +// [SPARC] needs-llvm-components: sparc -//@ revisions: MIPS64EL MIPS -//@ [MIPS64EL] compile-flags: --target mips64el-unknown-linux-gnuabi64 -//@ [MIPS64EL] needs-llvm-components: mips -//@ [MIPS] compile-flags: --target mips-unknown-linux-gnu -//@ [MIPS] needs-llvm-components: mips +// revisions: S390X +// [S390X] compile-flags: --target s390x-unknown-linux-gnu +// [S390X] needs-llvm-components: systemz -//@ revisions: WASM32 WASM64 -//@ [WASM32] compile-flags: --target wasm32-unknown-unknown -//@ [WASM32] needs-llvm-components: webassembly -//@ [WASM64] compile-flags: --target wasm64-unknown-unknown -//@ [WASM64] needs-llvm-components: webassembly +// revisions: POWERPC POWERPC64LE POWERPC64 AIX +// [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu +// [POWERPC] needs-llvm-components: powerpc +// [POWERPC64LE] compile-flags: --target powerpc64le-unknown-linux-gnu +// [POWERPC64LE] needs-llvm-components: powerpc +// [POWERPC64] compile-flags: --target powerpc64-unknown-linux-gnu +// [POWERPC64] needs-llvm-components: powerpc +// [AIX] compile-flags: --target powerpc64-ibm-aix +// [AIX] needs-llvm-components: powerpc -//@ revisions: CSKY -//@ [CSKY] compile-flags: --target csky-unknown-linux-gnuabiv2 -//@ [CSKY] needs-llvm-components: csky +// revisions: MIPS64EL MIPS +// [MIPS64EL] compile-flags: --target mips64el-unknown-linux-gnuabi64 +// [MIPS64EL] needs-llvm-components: mips +// [MIPS] compile-flags: --target mips-unknown-linux-gnu +// [MIPS] needs-llvm-components: mips -//@ revisions: NVPTX -//@ [NVPTX] compile-flags: --target nvptx64-nvidia-cuda -//@ [NVPTX] needs-llvm-components: nvptx +// revisions: WASM32 WASM64 +// [WASM32] compile-flags: --target wasm32-unknown-unknown +// [WASM32] needs-llvm-components: webassembly +// [WASM64] compile-flags: --target wasm64-unknown-unknown +// [WASM64] needs-llvm-components: webassembly -//@ revisions: BPF -//@ [BPF] compile-flags: --target bpfel-unknown-none -//@ [BPF] needs-llvm-components: bpf +// revisions: CSKY +// [CSKY] compile-flags: --target csky-unknown-linux-gnuabiv2 +// [CSKY] needs-llvm-components: csky + +// revisions: NVPTX +// [NVPTX] compile-flags: --target nvptx64-nvidia-cuda +// [NVPTX] needs-llvm-components: nvptx + +// revisions: BPF +// [BPF] compile-flags: --target bpfel-unknown-none +// [BPF] needs-llvm-components: bpf #![feature(no_core, lang_items, repr_complex, f16, f128)] #![no_core] From fac1794ac3c189cac1984c2a29a0906dbfef172f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 6 Jul 2026 23:41:57 +0200 Subject: [PATCH 10/10] Implement and test x86_64 Complex --- tests/codegen-llvm/complex-abi.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/codegen-llvm/complex-abi.rs b/tests/codegen-llvm/complex-abi.rs index 9d79cb0889fd4..42fd04a48172d 100644 --- a/tests/codegen-llvm/complex-abi.rs +++ b/tests/codegen-llvm/complex-abi.rs @@ -119,7 +119,7 @@ pub extern "C" fn cplx_f16(x: Complex) -> Complex { // WIN32_MSVC: define{{.*}} <2 x half> @cplx_f16(ptr {{.*}} byval({ half, half }) {{.*}}) // WINDOWS_GNU: define{{.*}} i32 @cplx_f16(i32 {{.*}}) // WINDOWS_MSVC: define{{.*}} i32 @cplx_f16(i32 {{.*}}) - // X86_64: define{{.*}} <2 x half> @cplx_f16(<2 x half> {{.*}}) + // X86_64: define{{.*}} float @cplx_f16(float {{.*}}) x } @@ -153,7 +153,7 @@ pub extern "C" fn cplx_f32(x: Complex) -> Complex { // WIN32_MSVC: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) // WINDOWS_GNU: define{{.*}} i64 @cplx_f32(i64 {{.*}}) // WINDOWS_MSVC: define{{.*}} i64 @cplx_f32(i64 {{.*}}) - // X86_64: define{{.*}} <2 x float> @cplx_f32(<2 x float> {{.*}}) + // X86_64: define{{.*}} double @cplx_f32(double {{.*}}) x } @@ -185,9 +185,9 @@ pub extern "C" fn cplx_f64(x: Complex) -> Complex { // WASM64: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) // WIN32_GNU: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) // WIN32_MSVC: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) - // WINDOWS_GNU: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}}) - // WINDOWS_MSVC: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}}) - // X86_64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // WINDOWS_GNU: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) + // WINDOWS_MSVC: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) + // X86_64: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) x } @@ -197,8 +197,8 @@ pub extern "C" fn cplx_f128(x: Complex) -> Complex { // WASM32: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) // WASM64: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) // WIN32_GNU: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) - // WINDOWS_GNU: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}}) - // X86_64: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) + // WINDOWS_GNU: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) + // X86_64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}} byval([32 x i8]) {{.*}}) x } @@ -332,8 +332,8 @@ pub extern "C" fn cplx_i64(x: Complex) -> Complex { // WASM64: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) // WIN32_GNU: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) // WIN32_MSVC: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) - // WINDOWS_GNU: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) - // WINDOWS_MSVC: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) - // X86_64: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) + // WINDOWS_GNU: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) + // WINDOWS_MSVC: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) + // X86_64: define{{.*}} { i64, i64 } @cplx_i64({ i64, i64 } {{.*}}) x }