Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions compiler/rustc_abi/src/layout/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_number(this: TyAndLayout<'a, Self>, cx: &C) -> 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;
Expand Down Expand Up @@ -227,6 +228,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Ty::is_transparent(self)
}

pub fn is_complex_number<C>(self, cx: &C) -> bool
Comment thread
folkertdev marked this conversation as resolved.
where
Ty: TyAbiInterface<'a, C> + Copy,
{
Ty::is_complex_number(self.peel_transparent_wrappers(cx), cx)
}

pub fn is_scalable_vector<C>(self) -> bool
where
Ty: TyAbiInterface<'a, C>,
Expand Down Expand Up @@ -291,6 +299,26 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
found
}

pub fn complex_float<C>(&self, cx: &C) -> Option<Float>
where
Ty: TyAbiInterface<'a, C> + Copy,
{
if !Ty::is_complex_number(*self, cx) {
return None;
}

let BackendRepr::ScalarPair { a, b, .. } = self.backend_repr else {
return None;
};

debug_assert_eq!(a, b);

match a.primitive() {
Primitive::Float(f) => Some(f),
_ => None,
}
}

/// Whether this type/layout has any padding that is dependent on a variant, i.e. has bytes that
/// are padding for some, but not all, valid values of this type.
pub fn has_variant_dependent_padding<C>(&self, cx: &C) -> bool
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_ir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ language_item_table! {
VaArgSafe, sym::va_arg_safe, va_arg_safe, Target::Trait, GenericRequirement::None;
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;

Complex, sym::complex, complex, Target::Struct, GenericRequirement::Exact(1);

Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0);
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,20 @@ where
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
}

/// Does this type have a layout compatible with C `_Complex`?
///
/// The value must be of type `core::num::Complex<T>` where `T` is numeric.
fn is_complex_number(this: TyAndLayout<'tcx>, cx: &C) -> bool {
let ty::Adt(def, generic_args) = this.ty.kind() else { return false };

if !cx.tcx().is_lang_item(def.did(), LangItem::Complex) {
return false;
}

// Only Complex<{ float }> and Complex<{ integer }> have special layout.
generic_args.type_at(0).is_numeric()
}

fn is_scalable_vector(this: TyAndLayout<'tcx>) -> bool {
this.ty.is_scalable_vector()
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ symbols! {
compiler_copy,
compiler_fence,
compiler_move,
complex,
concat,
concat_bytes,
conservative_impl_trait,
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_target/src/callconv/x86.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_abi::{
AddressSpace, Align, BackendRepr, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout,
AddressSpace, Align, BackendRepr, Float, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout,
};

use crate::callconv::{ArgAttribute, FnAbi, PassMode, TyAbiInterface};
Expand Down Expand Up @@ -32,7 +32,14 @@ where
// https://www.angelcode.com/dev/callconv/callconv.html
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
let t = cx.target_spec();
if t.abi_return_struct_as_int || opts.reg_struct_return {
if let Some(Float::F16) = fn_abi.ret.layout.complex_float(cx) {
// `_Complex _Float16` is returned as `<2 x half>`.
let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) };
fn_abi.ret.cast_to(Reg { kind, size: fn_abi.ret.layout.size });
} else if t.abi_return_struct_as_int
|| opts.reg_struct_return
|| fn_abi.ret.layout.is_complex_number(cx)
{
// According to Clang, everyone but MSVC returns single-element
// float aggregates directly in a floating-point register.
if fn_abi.ret.layout.is_single_fp_element(cx) {
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_target/src/callconv/x86_win32.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rustc_abi::{Align, HasDataLayout, Reg, TyAbiInterface};
use rustc_abi::{Align, Float, HasDataLayout, Primitive, Reg, RegKind, TyAbiInterface};

use crate::callconv::FnAbi;
use crate::spec::HasTargetSpec;
Expand All @@ -25,7 +25,11 @@ pub(crate) fn compute_abi_info<'a, Ty, C>(
// GCC used to apply the SysV rule here, breaking windows-gnu's ABI, but was fixed:
// - reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
// - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667
if t.abi_return_struct_as_int || opts.reg_struct_return {
if let Some(Float::F16) = fn_abi.ret.layout.complex_float(cx) {
// `_Complex _Float16` is returned as `<2 x half>`.
let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) };
fn_abi.ret.cast_to(Reg { kind, size: fn_abi.ret.layout.size });
} else if t.abi_return_struct_as_int || opts.reg_struct_return {
match fn_abi.ret.layout.size.bytes() {
1 => fn_abi.ret.cast_to(Reg::i8()),
2 => fn_abi.ret.cast_to(Reg::i16()),
Expand Down
20 changes: 20 additions & 0 deletions library/core/src/num/complex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/// A complex number.
#[derive(Clone, Copy, Debug, PartialEq)]
#[unstable(feature = "complex_numbers", issue = "154023")]
#[repr(C)]
#[lang = "complex"]
pub struct Complex<T> {
/// The real component.
pub re: T,
/// The imaginary component.
pub im: T,
Comment on lines +8 to +10

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, odd. I kind of would expect r and i or real and imaginary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be some value in matching the C function names real and imag, but I don't personally think it's compelling:
https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Complex-Data-Types.html

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just following the RFC here, libs can re-litigate it later

}
Comment on lines +6 to +11

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure if public fields is desirable here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having to call a method just to get the real or imaginary part seems annoying

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again this is just per the RFC #154023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, OK, I didn't notice that on my scan.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving this open so I see it if I revisit this PR for some reason, but considering it nonblocking.


#[unstable(feature = "complex_numbers", issue = "154023")]
impl<T> Complex<T> {
/// Create a new complex number from a real and imaginary component.
#[must_use]
pub fn new(re: T, im: T) -> Complex<T> {
Complex { re, im }
}
}
3 changes: 3 additions & 0 deletions library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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")]
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
13 changes: 13 additions & 0 deletions tests/auxiliary/minicore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,19 @@ pub mod hint {
}
}

pub mod num {
use super::Copy;

#[repr(C)]
#[lang = "complex"]
pub struct Complex<T> {
pub re: T,
pub im: T,
}

impl<T: Copy> Copy for Complex<T> {}
}

#[lang = "c_void"]
#[repr(u8)]
pub enum c_void {
Expand Down
Loading
Loading