From 398698864b467b7facf5f7f1557ea2fec2d6912e Mon Sep 17 00:00:00 2001 From: Andy Ly Date: Thu, 12 Nov 2026 19:50:28 -0800 Subject: [PATCH] Fix f32 and f64 constant literal generation in cc_bindings_from_rs. `scalar_value_to_string` previously formatted `f32` and `f64` constants solely via `rustc_apfloat` `Display`, suffixing `f64` (`double`) literals with `L` (`long double`) and emitting invalid C++ tokens (`+Inf.0f`, `-Inf.0f`, `NaN.0f`) for non-finite values. Classify target IEEE-754 values via `rustc_apfloat` (`Category`, `Float`, and `ieee::Semantics`) without host float casts: emit signed `0.0` for zeros, `rustc_apfloat` `Display` literals with `"f"` and `""` suffixes for finite `f32` and `f64` values, and Clang/GCC `constexpr` builtins (`__builtin_inf[f]()` and `__builtin_nan[s][f](...)`) for infinities and NaNs preserving sign, quiet/signaling bit, and payload. Remove the `unsupported_consts` workaround for `core::{f32,f64}::{INFINITY,NEG_INFINITY,NAN}`, and exclude `rustc_apfloat` from generated OSS `Cargo.toml` dependencies where `rustc-dev` provides it via `rustc_private`. PiperOrigin-RevId: 1020654379 --- .../generate_bindings_test.rs | 170 ++++++++++++++++++ .../generate_bindings/generate_enum.rs | 43 +++-- .../generate_struct_and_union.rs | 19 +- .../test/bazel/rs_core/rs_core_test.cc | 25 +++ cc_bindings_from_rs/test/consts/consts.rs | 73 +++++++- .../test/consts/consts_cc_api.h | 125 ++++++++++++- .../test/consts/consts_cc_api_impl.rs | 20 +++ .../test/consts/consts_test.cc | 133 ++++++++++++++ .../consts/goldens/android_32/consts_cc_api.h | 125 ++++++++++++- .../goldens/android_32/consts_cc_api_impl.rs | 20 +++ .../consts/goldens/windows_32/consts_cc_api.h | 125 ++++++++++++- .../goldens/windows_32/consts_cc_api_impl.rs | 20 +++ 12 files changed, 849 insertions(+), 49 deletions(-) diff --git a/cc_bindings_from_rs/generate_bindings/generate_bindings_test.rs b/cc_bindings_from_rs/generate_bindings/generate_bindings_test.rs index 8d261437b2..9cbd6f1717 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_bindings_test.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_bindings_test.rs @@ -2534,6 +2534,176 @@ fn test_const_non_aggregate_struct_fails() { }); } +#[gtest] +fn test_const_float() { + let test_src = r#" + pub const WHOLE_F32: f32 = 64.0; + pub const LARGE_WHOLE_F32: f32 = 12583039.0; + pub const SCI_F32: f32 = 1e-7; + pub const NEG_ZERO_F32: f32 = -0.0; + pub const INF_F32: f32 = f32::INFINITY; + pub const NEG_INF_F32: f32 = f32::NEG_INFINITY; + pub const NAN_F32: f32 = f32::NAN; + pub const NEG_NAN_F32: f32 = -f32::NAN; + pub const PAYLOAD_NAN_F32: f32 = f32::from_bits(0x7fc0_0042); + pub const NEG_PAYLOAD_NAN_F32: f32 = f32::from_bits(0xffc0_0042); + pub const MAX_PAYLOAD_NAN_F32: f32 = f32::from_bits(0x7fff_ffff); + pub const SIGNALING_NAN_F32: f32 = f32::from_bits(0x7f80_0001); + pub const NEG_SIGNALING_NAN_F32: f32 = f32::from_bits(0xff80_0001); + pub const WHOLE_F64: f64 = 64.0; + pub const INF_F64: f64 = f64::INFINITY; + pub const NEG_INF_F64: f64 = f64::NEG_INFINITY; + pub const NAN_F64: f64 = f64::NAN; + pub const NEG_NAN_F64: f64 = -f64::NAN; + pub const PAYLOAD_NAN_F64: f64 = f64::from_bits(0x7ff8_0000_0000_0042); + pub const NEG_PAYLOAD_NAN_F64: f64 = f64::from_bits(0xfff8_0000_0000_0042); + pub const MAX_PAYLOAD_NAN_F64: f64 = f64::from_bits(0x7fff_ffff_ffff_ffff); + pub const SIGNALING_NAN_F64: f64 = f64::from_bits(0x7ff0_0000_0000_0001); + pub const NEG_SIGNALING_NAN_F64: f64 = f64::from_bits(0xfff0_0000_0000_0001); + "#; + test_generated_bindings(test_src, |bindings| { + let cc_api = &bindings.unwrap().cc_api; + assert_cc_matches!( + cc_api, + quote! { + static constexpr float WHOLE_F32 = 64.0f; + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float LARGE_WHOLE_F32 = 12583039.0f; + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float SCI_F32 = 1.00000001E-7f; + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float NEG_ZERO_F32 = -0.0f; + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float INF_F32 = __builtin_inff(); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float NEG_INF_F32 = -__builtin_inff(); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float NAN_F32 = __builtin_nanf(""); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float NEG_NAN_F32 = -__builtin_nanf(""); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float PAYLOAD_NAN_F32 = __builtin_nanf("0x42"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float NEG_PAYLOAD_NAN_F32 = -__builtin_nanf("0x42"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float MAX_PAYLOAD_NAN_F32 = __builtin_nanf("0x3fffff"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float SIGNALING_NAN_F32 = __builtin_nansf("0x1"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr float NEG_SIGNALING_NAN_F32 = -__builtin_nansf("0x1"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double WHOLE_F64 = 64.0; + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double INF_F64 = __builtin_inf(); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double NEG_INF_F64 = -__builtin_inf(); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double NAN_F64 = __builtin_nan(""); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double NEG_NAN_F64 = -__builtin_nan(""); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double PAYLOAD_NAN_F64 = __builtin_nan("0x42"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double NEG_PAYLOAD_NAN_F64 = -__builtin_nan("0x42"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double MAX_PAYLOAD_NAN_F64 = __builtin_nan("0x7ffffffffffff"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double SIGNALING_NAN_F64 = __builtin_nans("0x1"); + } + ); + assert_cc_matches!( + cc_api, + quote! { + static constexpr double NEG_SIGNALING_NAN_F64 = -__builtin_nans("0x1"); + } + ); + }); +} + #[gtest] fn test_unbindable_types_warning() { let test_src = r#" diff --git a/cc_bindings_from_rs/generate_bindings/generate_enum.rs b/cc_bindings_from_rs/generate_bindings/generate_enum.rs index f6e0a9cf25..c9d8944cff 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_enum.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_enum.rs @@ -14,6 +14,7 @@ #![feature(stmt_expr_attributes)] extern crate rustc_abi; +extern crate rustc_apfloat; extern crate rustc_middle; extern crate rustc_span; @@ -33,6 +34,7 @@ use rustc_abi::{ FieldIdx, FieldsShape, Integer, IntegerType, Layout, Primitive, TagEncoding, VariantIdx, Variants, }; +use rustc_apfloat::{ieee, Category, Float}; use rustc_middle::mir::interpret::Scalar; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, TyCtxt, TyKind}; @@ -674,6 +676,29 @@ fn generate_variant<'tcx>( } } +/// Formats a target IEEE-754 float into a C++ `constexpr` literal or Clang/GCC builtin call, +/// preserving `-0.0`, subnormals, infinities, and NaN sign, quiet/signaling bit, and payload. +fn format_apfloat(value: ieee::IeeeFloat, suffix: &str) -> String { + let sign = if value.is_negative() { "-" } else { "" }; + match value.category() { + Category::Infinity => format!("{sign}__builtin_inf{suffix}()"), + Category::NaN => { + let payload = value.to_bits() & S::NAN_PAYLOAD_MASK & !S::QNAN_SIGNIFICAND; + if payload == 0 { + format!(r#"{sign}__builtin_nan{suffix}("")"#) + } else { + let sig = if value.is_signaling() { "s" } else { "" }; + format!(r#"{sign}__builtin_nan{sig}{suffix}("0x{payload:x}")"#) + } + } + Category::Zero | Category::Normal => { + let s = value.to_string(); + let dot_zero = if s.contains(['.', 'e', 'E']) { "" } else { ".0" }; + format!("{s}{dot_zero}{suffix}") + } + } +} + /// Returns a string representation of the value of a given numeric Scalar having a given TyKind. pub fn scalar_value_to_string(tcx: TyCtxt, scalar: Scalar, kind: TyKind) -> Result { let scalar = match scalar { @@ -695,14 +720,6 @@ pub fn scalar_value_to_string(tcx: TyCtxt, scalar: Scalar, kind: TyKind) -> Resu use ty::TyKind; use ty::UintTy::*; - fn format_float(value: String, suffix: &str) -> String { - if value.contains('.') || value.contains('e') || value.contains('E') { - format!("{value}{suffix}") - } else { - format!("{value}.0{suffix}") - } - } - Ok(match kind { TyKind::Bool => scalar.try_to_bool().unwrap().to_string(), TyKind::Int(I8) => scalar.to_i8().to_string(), @@ -712,14 +729,8 @@ pub fn scalar_value_to_string(tcx: TyCtxt, scalar: Scalar, kind: TyKind) -> Resu TyKind::Uint(U16) => format!("UINT16_C({})", scalar.to_u16()), TyKind::Uint(U32) => format!("UINT32_C({})", scalar.to_u32()), TyKind::Uint(U64) => format!("UINT64_C({})", scalar.to_u64()), - TyKind::Float(F32) => { - let s = scalar.to_f32().to_string(); - format_float(s, "f") - } - TyKind::Float(F64) => { - let s = scalar.to_f64().to_string(); - format_float(s, "L") - } + TyKind::Float(F32) => format_apfloat(scalar.to_f32(), "f"), + TyKind::Float(F64) => format_apfloat(scalar.to_f64(), ""), TyKind::Uint(Usize) => format!("UINT64_C({})", scalar.to_target_usize(tcx)), // Signed integer minimums cannot be expressed with literals, as `-` parses as a unary diff --git a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs index 89dd571566..0348faf1f6 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs @@ -48,8 +48,8 @@ use itertools::Itertools; use proc_macro2::{Ident, Literal, TokenStream}; use query_compiler::{ as_ref_or_pinned_ref, field_def_is_pub_and_stable, get_layout, get_tag_size_with_padding, - get_validated_layout, is_copy, is_std_ptr_non_null, matches_qualified_name, normalize_ty, - should_receive_bindings, SortedByDef, + get_validated_layout, is_copy, is_std_ptr_non_null, normalize_ty, should_receive_bindings, + SortedByDef, }; use quote::{format_ident, quote}; #[rustversion::since(2026-05-18)] @@ -4406,21 +4406,6 @@ pub fn generate_const<'tcx>( bail!("Associated constants with their own predicates are not supported"); } } - // TODO: b/457843120 - Remove this workaround once we can properly support float constants. - let unsupported_consts = [ - ["core", "f32", "INFINITY"], - ["core", "f64", "INFINITY"], - ["core", "f32", "NEG_INFINITY"], - ["core", "f64", "NEG_INFINITY"], - ["core", "f32", "NAN"], - ["core", "f64", "NAN"], - ]; - if unsupported_consts.iter().any(|const_path| matches_qualified_name(db, def_id, const_path)) { - bail!( - "Cannot generate bindings to unsupported constant: {}", - tcx.item_name(def_id).as_str() - ) - } let (ty, const_value) = match generic_args { Some(args) => { let typing_env = ty::TypingEnv::fully_monomorphized(); diff --git a/cc_bindings_from_rs/test/bazel/rs_core/rs_core_test.cc b/cc_bindings_from_rs/test/bazel/rs_core/rs_core_test.cc index 2df2e57330..e584e6d702 100644 --- a/cc_bindings_from_rs/test/bazel/rs_core/rs_core_test.cc +++ b/cc_bindings_from_rs/test/bazel/rs_core/rs_core_test.cc @@ -2,7 +2,11 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// Verify that macros (INFINITY, NAN) do not collide with rs_core.h. +// clang-format off +#include #include "support/rs_std/rs_core.h" +// clang-format on #include "gtest/gtest.h" @@ -14,5 +18,26 @@ TEST(RsCoreTest, Duration) { EXPECT_EQ(d.as_secs(), 10); } +TEST(RsCoreTest, FloatConstants) { + static_assert(rs::core::f32::INFINITY_ == __builtin_inff()); + static_assert(rs::core::f32::NEG_INFINITY == -__builtin_inff()); + static_assert(rs::core::f32::NAN_ != rs::core::f32::NAN_); + static_assert(rs::core::f64::INFINITY_ == __builtin_inf()); + static_assert(rs::core::f64::NEG_INFINITY == -__builtin_inf()); + static_assert(rs::core::f64::NAN_ != rs::core::f64::NAN_); + + EXPECT_TRUE(std::isinf(rs::core::f32::INFINITY_)); + EXPECT_GT(rs::core::f32::INFINITY_, 0.0f); + EXPECT_TRUE(std::isinf(rs::core::f32::NEG_INFINITY)); + EXPECT_LT(rs::core::f32::NEG_INFINITY, 0.0f); + EXPECT_TRUE(std::isnan(rs::core::f32::NAN_)); + + EXPECT_TRUE(std::isinf(rs::core::f64::INFINITY_)); + EXPECT_GT(rs::core::f64::INFINITY_, 0.0); + EXPECT_TRUE(std::isinf(rs::core::f64::NEG_INFINITY)); + EXPECT_LT(rs::core::f64::NEG_INFINITY, 0.0); + EXPECT_TRUE(std::isnan(rs::core::f64::NAN_)); +} + } // namespace } // namespace crubit diff --git a/cc_bindings_from_rs/test/consts/consts.rs b/cc_bindings_from_rs/test/consts/consts.rs index 91eecea6a0..ba8590b8ca 100644 --- a/cc_bindings_from_rs/test/consts/consts.rs +++ b/cc_bindings_from_rs/test/consts/consts.rs @@ -33,17 +33,49 @@ use crubit_annotate::must_bind; #[must_bind] pub const RUST_USIZE_MAX: isize = isize::MAX; #[must_bind] pub const RUST_F32_MIN: f32 = f32::MIN; #[must_bind] pub const RUST_F32_MAX: f32 = f32::MAX; +#[must_bind] pub const RUST_F32_MIN_POSITIVE: f32 = f32::MIN_POSITIVE; +#[must_bind] pub const RUST_F32_EPSILON: f32 = f32::EPSILON; #[must_bind] pub const RUST_F64_MIN: f64 = f64::MIN; #[must_bind] pub const RUST_F64_MAX: f64 = f64::MAX; +#[must_bind] pub const RUST_F64_MIN_POSITIVE: f64 = f64::MIN_POSITIVE; +#[must_bind] pub const RUST_F64_EPSILON: f64 = f64::EPSILON; #[must_bind] pub const INT_POS: i32 = 42; #[must_bind] pub const INT_NEG: i32 = -17; #[must_bind] pub const FLOAT_32: f32 = 0.125; // 2^(-3) -#[must_bind] pub const FLOAT_64: f64 = 0.0078125; // 2^(-7) #[must_bind] pub const FLOAT_32_ZERO: f32 = 0.0; #[must_bind] pub const FLOAT_32_ONE: f32 = 1.0; +#[must_bind] pub const FLOAT_32_WHOLE: f32 = 64.0; +#[must_bind] pub const FLOAT_32_NEG_ZERO: f32 = -0.0; +#[must_bind] pub const FLOAT_32_MIN_SUBNORMAL: f32 = f32::from_bits(1); +#[must_bind] pub const FLOAT_32_MAX_SUBNORMAL: f32 = f32::from_bits(0x007f_ffff); +#[must_bind] pub const FLOAT_32_NEG_SUBNORMAL: f32 = f32::from_bits(0x8000_0001); +#[must_bind] pub const FLOAT_32_INFINITY: f32 = f32::INFINITY; +#[must_bind] pub const FLOAT_32_NEG_INFINITY: f32 = f32::NEG_INFINITY; +#[must_bind] pub const FLOAT_32_NAN: f32 = f32::NAN; +#[must_bind] pub const FLOAT_32_NEG_NAN: f32 = -f32::NAN; +#[must_bind] pub const FLOAT_32_PAYLOAD_NAN: f32 = f32::from_bits(0x7fc0_0042); +#[must_bind] pub const FLOAT_32_NEG_PAYLOAD_NAN: f32 = f32::from_bits(0xffc0_0042); +#[must_bind] pub const FLOAT_32_MAX_PAYLOAD_NAN: f32 = f32::from_bits(0x7fff_ffff); +#[must_bind] pub const FLOAT_32_SIGNALING_NAN: f32 = f32::from_bits(0x7f80_0001); +#[must_bind] pub const FLOAT_32_NEG_SIGNALING_NAN: f32 = f32::from_bits(0xff80_0001); +#[must_bind] pub const FLOAT_64: f64 = 0.0078125; // 2^(-7) #[must_bind] pub const FLOAT_64_ZERO: f64 = 0.0; #[must_bind] pub const FLOAT_64_ONE: f64 = 1.0; +#[must_bind] pub const FLOAT_64_WHOLE: f64 = 64.0; +#[must_bind] pub const FLOAT_64_NEG_ZERO: f64 = -0.0; +#[must_bind] pub const FLOAT_64_MIN_SUBNORMAL: f64 = f64::from_bits(1); +#[must_bind] pub const FLOAT_64_MAX_SUBNORMAL: f64 = f64::from_bits(0x000f_ffff_ffff_ffff); +#[must_bind] pub const FLOAT_64_NEG_SUBNORMAL: f64 = f64::from_bits(0x8000_0000_0000_0001); +#[must_bind] pub const FLOAT_64_INFINITY: f64 = f64::INFINITY; +#[must_bind] pub const FLOAT_64_NEG_INFINITY: f64 = f64::NEG_INFINITY; +#[must_bind] pub const FLOAT_64_NAN: f64 = f64::NAN; +#[must_bind] pub const FLOAT_64_NEG_NAN: f64 = -f64::NAN; +#[must_bind] pub const FLOAT_64_PAYLOAD_NAN: f64 = f64::from_bits(0x7ff8_0000_0000_0042); +#[must_bind] pub const FLOAT_64_NEG_PAYLOAD_NAN: f64 = f64::from_bits(0xfff8_0000_0000_0042); +#[must_bind] pub const FLOAT_64_MAX_PAYLOAD_NAN: f64 = f64::from_bits(0x7fff_ffff_ffff_ffff); +#[must_bind] pub const FLOAT_64_SIGNALING_NAN: f64 = f64::from_bits(0x7ff0_0000_0000_0001); +#[must_bind] pub const FLOAT_64_NEG_SIGNALING_NAN: f64 = f64::from_bits(0xfff0_0000_0000_0001); #[must_bind] pub const LARGE_INT: i64 = 9223372036854775807; #[must_bind] pub const UNSIGNED_INT: u32 = 4294967295; #[must_bind] pub const SLICE_LENGTH: usize = "hello world".len(); @@ -94,6 +126,45 @@ pub const NESTED_STRUCT_CONST: NestedStruct = NestedStruct { #[must_bind] pub const ARRAY_CONST: [i32; 3] = [10, 20, 30]; +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct FloatStruct { + pub x: f32, + pub y: f32, +} + +#[must_bind] +pub const FLOAT_STRUCT_CONST: FloatStruct = FloatStruct { + x: -0.0, + y: f32::INFINITY, +}; + +#[must_bind] +pub const FLOAT_ARRAY_CONST: [f32; 4] = [64.0, -0.0, f32::NEG_INFINITY, f32::NAN]; + +#[must_bind] +pub const FLOAT_64_ARRAY_CONST: [f64; 2] = [-0.0, f64::INFINITY]; + +#[must_bind] +pub fn f32_to_bits(x: f32) -> u32 { + x.to_bits() +} + +#[must_bind] +pub fn f64_to_bits(x: f64) -> u64 { + x.to_bits() +} + +#[must_bind] +pub fn roundtrip_f32(x: f32) -> f32 { + x +} + +#[must_bind] +pub fn roundtrip_f64(x: f64) -> f64 { + x +} + #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct StructWithArray { pub values: [i32; 2], diff --git a/cc_bindings_from_rs/test/consts/consts_cc_api.h b/cc_bindings_from_rs/test/consts/consts_cc_api.h index b7ac04217b..fa57cfb5d6 100644 --- a/cc_bindings_from_rs/test/consts/consts_cc_api.h +++ b/cc_bindings_from_rs/test/consts/consts_cc_api.h @@ -34,11 +34,55 @@ static constexpr ::std::array<::std::int32_t, 3> ARRAY_CONST = ::std::array<::std::int32_t, 3>{INT32_C(10), INT32_C(20), INT32_C(30)}; static constexpr decltype(char(0)) CHAR = 42; static constexpr float FLOAT_32 = 0.125f; +static constexpr float FLOAT_32_INFINITY = __builtin_inff(); +static constexpr float FLOAT_32_MAX_PAYLOAD_NAN = __builtin_nanf("0x3fffff"); +static constexpr float FLOAT_32_MAX_SUBNORMAL = 1.17549421E-38f; +static constexpr float FLOAT_32_MIN_SUBNORMAL = 1.40129846E-45f; +static constexpr float FLOAT_32_NAN = __builtin_nanf(""); +static constexpr float FLOAT_32_NEG_INFINITY = -__builtin_inff(); +static constexpr float FLOAT_32_NEG_NAN = -__builtin_nanf(""); +static constexpr float FLOAT_32_NEG_PAYLOAD_NAN = -__builtin_nanf("0x42"); +static constexpr float FLOAT_32_NEG_SIGNALING_NAN = -__builtin_nansf("0x1"); +static constexpr float FLOAT_32_NEG_SUBNORMAL = -1.40129846E-45f; +static constexpr float FLOAT_32_NEG_ZERO = -0.0f; static constexpr float FLOAT_32_ONE = 1.0f; +static constexpr float FLOAT_32_PAYLOAD_NAN = __builtin_nanf("0x42"); +static constexpr float FLOAT_32_SIGNALING_NAN = __builtin_nansf("0x1"); +static constexpr float FLOAT_32_WHOLE = 64.0f; static constexpr float FLOAT_32_ZERO = 0.0f; -static constexpr double FLOAT_64 = 0.0078125L; -static constexpr double FLOAT_64_ONE = 1.0L; -static constexpr double FLOAT_64_ZERO = 0.0L; +static constexpr double FLOAT_64 = 0.0078125; +static constexpr ::std::array FLOAT_64_ARRAY_CONST = + ::std::array{-0.0, __builtin_inf()}; +static constexpr double FLOAT_64_INFINITY = __builtin_inf(); +static constexpr double FLOAT_64_MAX_PAYLOAD_NAN = + __builtin_nan("0x7ffffffffffff"); +static constexpr double FLOAT_64_MAX_SUBNORMAL = 2.2250738585072009E-308; +static constexpr double FLOAT_64_MIN_SUBNORMAL = 4.9406564584124654E-324; +static constexpr double FLOAT_64_NAN = __builtin_nan(""); +static constexpr double FLOAT_64_NEG_INFINITY = -__builtin_inf(); +static constexpr double FLOAT_64_NEG_NAN = -__builtin_nan(""); +static constexpr double FLOAT_64_NEG_PAYLOAD_NAN = -__builtin_nan("0x42"); +static constexpr double FLOAT_64_NEG_SIGNALING_NAN = -__builtin_nans("0x1"); +static constexpr double FLOAT_64_NEG_SUBNORMAL = -4.9406564584124654E-324; +static constexpr double FLOAT_64_NEG_ZERO = -0.0; +static constexpr double FLOAT_64_ONE = 1.0; +static constexpr double FLOAT_64_PAYLOAD_NAN = __builtin_nan("0x42"); +static constexpr double FLOAT_64_SIGNALING_NAN = __builtin_nans("0x1"); +static constexpr double FLOAT_64_WHOLE = 64.0; +static constexpr double FLOAT_64_ZERO = 0.0; +static constexpr ::std::array FLOAT_ARRAY_CONST = + ::std::array{64.0f, -0.0f, -__builtin_inff(), __builtin_nanf("")}; +struct CRUBIT_INTERNAL_RUST_TYPE(":: consts_golden :: FloatStruct") + [[clang::trivial_abi]] FloatStruct final { + public: + float x{}; + float y{}; + + private: + static void __crubit_field_offset_assertions(); +}; +static constexpr ::consts::FloatStruct FLOAT_STRUCT_CONST = + ::consts::FloatStruct{.x = -0.0f, .y = __builtin_inff()}; static constexpr ::std::int32_t INT_NEG = INT32_C(-17); static constexpr ::std::int32_t INT_POS = INT32_C(42); static constexpr ::std::intptr_t ISIZE = INT64_C(42); @@ -58,10 +102,14 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: consts_golden :: Point") }; static constexpr ::consts::Point POINT_CONST = ::consts::Point{.x = INT32_C(10), .y = INT32_C(-20)}; +static constexpr float RUST_F32_EPSILON = 1.1920929E-7f; static constexpr float RUST_F32_MAX = 3.40282347E+38f; static constexpr float RUST_F32_MIN = -3.40282347E+38f; -static constexpr double RUST_F64_MAX = 1.7976931348623157E+308L; -static constexpr double RUST_F64_MIN = -1.7976931348623157E+308L; +static constexpr float RUST_F32_MIN_POSITIVE = 1.17549435E-38f; +static constexpr double RUST_F64_EPSILON = 2.2204460492503131E-16; +static constexpr double RUST_F64_MAX = 1.7976931348623157E+308; +static constexpr double RUST_F64_MIN = -1.7976931348623157E+308; +static constexpr double RUST_F64_MIN_POSITIVE = 2.2250738585072014E-308; static constexpr bool RUST_FALSE = false; static constexpr ::std::int16_t RUST_INT16_MAX = 32767; static constexpr ::std::int16_t RUST_INT16_MIN = -32768; @@ -207,12 +255,35 @@ TyWithAssocConsts final { }; static constexpr ::std::uint32_t UNSIGNED_INT = UINT32_C(4294967295); +// CRUBIT_ANNOTATE: must_bind= +::std::uint32_t f32_to_bits(float x); + +// CRUBIT_ANNOTATE: must_bind= +::std::uint64_t f64_to_bits(double x); + // Error generating bindings for function // `consts_golden::fn_with_unreturnable_const`: Function contains a const block // that cannot return +// CRUBIT_ANNOTATE: must_bind= +float roundtrip_f32(float x); + +// CRUBIT_ANNOTATE: must_bind= +double roundtrip_f64(double x); + } // namespace consts +template <> +struct ::rs::impl<::consts::FloatStruct, ::rs::core::fmt::Debug> { + static constexpr bool kIsImplemented = true; + + // Error generating bindings for associated function + // `::fmt`: Error formatting + // function return type `std::result::Result<(), std::fmt::Error>`: Failed to + // format type for the definition of `std::fmt::Error`: Zero-sized types + // (ZSTs) are not supported (b/258259459) +}; + template <> struct ::rs::impl<::consts::NestedStruct, ::rs::core::cmp::Eq> { static constexpr bool kIsImplemented = true; @@ -311,6 +382,22 @@ struct ::rs::impl<::consts::TupleStruct, ::rs::core::fmt::Debug> { namespace consts { +static_assert( + sizeof(::consts::FloatStruct) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(::consts::FloatStruct) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_move_constructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_move_assignable_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_copy_constructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_copy_assignable_v<::consts::FloatStruct>); +inline void ::consts::FloatStruct::__crubit_field_offset_assertions() { + using __crubit_assert_type = ::consts::FloatStruct; + static_assert(0 == offsetof(__crubit_assert_type, x)); + static_assert(4 == offsetof(__crubit_assert_type, y)); +} static_assert( sizeof(::consts::NestedStruct) == 16, "Verify that ADT layout didn't change since this header got generated"); @@ -507,6 +594,34 @@ inline void ::consts::TyWithAssocConsts::__crubit_field_offset_assertions() { using __crubit_assert_type = ::consts::TyWithAssocConsts; static_assert(0 == offsetof(__crubit_assert_type, __field0)); } +namespace __crubit_internal { +extern "C" ::std::uint32_t __crubit_thunk_f32_uto_ubits(float); +} +inline ::std::uint32_t f32_to_bits(float x) { + return __crubit_internal::__crubit_thunk_f32_uto_ubits(x); +} + +namespace __crubit_internal { +extern "C" ::std::uint64_t __crubit_thunk_f64_uto_ubits(double); +} +inline ::std::uint64_t f64_to_bits(double x) { + return __crubit_internal::__crubit_thunk_f64_uto_ubits(x); +} + +namespace __crubit_internal { +extern "C" float __crubit_thunk_roundtrip_uf32(float); +} +inline float roundtrip_f32(float x) { + return __crubit_internal::__crubit_thunk_roundtrip_uf32(x); +} + +namespace __crubit_internal { +extern "C" double __crubit_thunk_roundtrip_uf64(double); +} +inline double roundtrip_f64(double x) { + return __crubit_internal::__crubit_thunk_roundtrip_uf64(x); +} + } // namespace consts #pragma clang diagnostic pop diff --git a/cc_bindings_from_rs/test/consts/consts_cc_api_impl.rs b/cc_bindings_from_rs/test/consts/consts_cc_api_impl.rs index d310a17147..f3295f5bde 100644 --- a/cc_bindings_from_rs/test/consts/consts_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/consts/consts_cc_api_impl.rs @@ -11,6 +11,10 @@ extern crate alloc; extern crate core; +const _: () = assert!(::core::mem::size_of::<::consts_golden::FloatStruct>() == 8); +const _: () = assert!(::core::mem::align_of::<::consts_golden::FloatStruct>() == 4); +const _: () = assert!(::core::mem::offset_of!(::consts_golden::FloatStruct, x) == 0); +const _: () = assert!(::core::mem::offset_of!(::consts_golden::FloatStruct, y) == 4); const _: () = assert!(::core::mem::size_of::<::consts_golden::NestedStruct>() == 16); const _: () = assert!(::core::mem::align_of::<::consts_golden::NestedStruct>() == 4); #[unsafe(no_mangle)] @@ -101,3 +105,19 @@ const _: () = assert!(::core::mem::offset_of!(::consts_golden::TupleStruct, 0) = const _: () = assert!(::core::mem::offset_of!(::consts_golden::TupleStruct, 1) == 4); const _: () = assert!(::core::mem::size_of::<::consts_golden::TyWithAssocConsts>() == 1); const _: () = assert!(::core::mem::align_of::<::consts_golden::TyWithAssocConsts>() == 1); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_f32_uto_ubits(x: f32) -> u32 { + unsafe { ::consts_golden::f32_to_bits(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_f64_uto_ubits(x: f64) -> u64 { + unsafe { ::consts_golden::f64_to_bits(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_roundtrip_uf32(x: f32) -> f32 { + unsafe { ::consts_golden::roundtrip_f32(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_roundtrip_uf64(x: f64) -> f64 { + unsafe { ::consts_golden::roundtrip_f64(x) } +} diff --git a/cc_bindings_from_rs/test/consts/consts_test.cc b/cc_bindings_from_rs/test/consts/consts_test.cc index 2d7c2f4c1c..68a54caa62 100644 --- a/cc_bindings_from_rs/test/consts/consts_test.cc +++ b/cc_bindings_from_rs/test/consts/consts_test.cc @@ -6,6 +6,10 @@ #include +#include +#include +#include + #include "gtest/gtest.h" namespace { @@ -34,11 +38,80 @@ TEST(ConstsTest, AllAreExpected) { // they're the smallest positive values. There are no standard constants for // the furthest negative floating-point values, so no assertion is made here. static_assert(consts::RUST_F32_MAX == FLT_MAX); + static_assert(consts::RUST_F32_MIN_POSITIVE == FLT_MIN); + static_assert(consts::RUST_F32_EPSILON == FLT_EPSILON); static_assert(consts::RUST_F64_MAX == DBL_MAX); + static_assert(consts::RUST_F64_MIN_POSITIVE == DBL_MIN); + static_assert(consts::RUST_F64_EPSILON == DBL_EPSILON); + static_assert(consts::FLOAT_32 == 0.125f); static_assert(consts::FLOAT_32_ZERO == 0.0f); static_assert(consts::FLOAT_32_ONE == 1.0f); + static_assert(consts::FLOAT_32_WHOLE == 64.0f); + static_assert(std::bit_cast(consts::FLOAT_32_NEG_ZERO) == + 0x80000000u); + static_assert(std::bit_cast(consts::FLOAT_32_MIN_SUBNORMAL) == 1u); + static_assert(std::bit_cast(consts::FLOAT_32_MAX_SUBNORMAL) == + 0x007fffffu); + static_assert(std::bit_cast(consts::FLOAT_32_NEG_SUBNORMAL) == + 0x80000001u); + static_assert(consts::FLOAT_32_INFINITY == __builtin_inff()); + static_assert(consts::FLOAT_32_NEG_INFINITY == -__builtin_inff()); + static_assert(consts::FLOAT_32_NAN != consts::FLOAT_32_NAN); + static_assert(std::bit_cast(consts::FLOAT_32_NAN) == 0x7fc00000u); + static_assert(std::bit_cast(consts::FLOAT_32_NEG_NAN) == + 0xffc00000u); + static_assert(std::bit_cast(consts::FLOAT_32_PAYLOAD_NAN) == + 0x7fc00042u); + static_assert(std::bit_cast(consts::FLOAT_32_NEG_PAYLOAD_NAN) == + 0xffc00042u); + static_assert(std::bit_cast(consts::FLOAT_32_MAX_PAYLOAD_NAN) == + 0x7fffffffu); + static_assert(std::bit_cast(consts::FLOAT_32_SIGNALING_NAN) == + 0x7f800001u); + static_assert(std::bit_cast(consts::FLOAT_32_NEG_SIGNALING_NAN) == + 0xff800001u); + static_assert(consts::FLOAT_64 == 0.0078125); static_assert(consts::FLOAT_64_ZERO == 0.0); static_assert(consts::FLOAT_64_ONE == 1.0); + static_assert(consts::FLOAT_64_WHOLE == 64.0); + static_assert(std::bit_cast(consts::FLOAT_64_NEG_ZERO) == + 0x8000000000000000ull); + static_assert(std::bit_cast(consts::FLOAT_64_MIN_SUBNORMAL) == + 1ull); + static_assert(std::bit_cast(consts::FLOAT_64_MAX_SUBNORMAL) == + 0x000fffffffffffffull); + static_assert(std::bit_cast(consts::FLOAT_64_NEG_SUBNORMAL) == + 0x8000000000000001ull); + static_assert(consts::FLOAT_64_INFINITY == __builtin_inf()); + static_assert(consts::FLOAT_64_NEG_INFINITY == -__builtin_inf()); + static_assert(consts::FLOAT_64_NAN != consts::FLOAT_64_NAN); + static_assert(std::bit_cast(consts::FLOAT_64_NAN) == + 0x7ff8000000000000ull); + static_assert(std::bit_cast(consts::FLOAT_64_NEG_NAN) == + 0xfff8000000000000ull); + static_assert(std::bit_cast(consts::FLOAT_64_PAYLOAD_NAN) == + 0x7ff8000000000042ull); + static_assert(std::bit_cast(consts::FLOAT_64_NEG_PAYLOAD_NAN) == + 0xfff8000000000042ull); + static_assert(std::bit_cast(consts::FLOAT_64_MAX_PAYLOAD_NAN) == + 0x7fffffffffffffffull); + static_assert(std::bit_cast(consts::FLOAT_64_SIGNALING_NAN) == + 0x7ff0000000000001ull); + static_assert(std::bit_cast(consts::FLOAT_64_NEG_SIGNALING_NAN) == + 0xfff0000000000001ull); + + static_assert(std::bit_cast(consts::FLOAT_STRUCT_CONST.x) == + 0x80000000u); + static_assert(consts::FLOAT_STRUCT_CONST.y == __builtin_inff()); + static_assert(consts::FLOAT_ARRAY_CONST[0] == 64.0f); + static_assert(std::bit_cast(consts::FLOAT_ARRAY_CONST[1]) == + 0x80000000u); + static_assert(consts::FLOAT_ARRAY_CONST[2] == -__builtin_inff()); + static_assert(std::bit_cast(consts::FLOAT_ARRAY_CONST[3]) == + 0x7fc00000u); + static_assert(std::bit_cast(consts::FLOAT_64_ARRAY_CONST[0]) == + 0x8000000000000000ull); + static_assert(consts::FLOAT_64_ARRAY_CONST[1] == __builtin_inf()); static_assert(consts::TyWithAssocConsts::ASSOC_42 == 42); static_assert(consts::TyWithAssocConsts::ASSOC_POINT.x == 5); @@ -76,4 +149,64 @@ TEST(ConstsTest, AllAreExpected) { static_assert(!std::is_default_constructible_v); } +TEST(ConstsTest, FloatRoundtrip) { + auto check_f32 = [](float float_value, uint32_t expected_bits) { + SCOPED_TRACE(testing::Message() + << "float_value=" << float_value << ", expected_bits=0x" + << std::hex << expected_bits); + EXPECT_EQ(std::bit_cast(float_value), expected_bits); + EXPECT_EQ(consts::f32_to_bits(float_value), expected_bits); + EXPECT_EQ(std::bit_cast(consts::roundtrip_f32(float_value)), + expected_bits); + }; + check_f32(consts::RUST_F32_MIN, 0xff7fffffu); + check_f32(consts::RUST_F32_MAX, 0x7f7fffffu); + check_f32(consts::RUST_F32_MIN_POSITIVE, 0x00800000u); + check_f32(consts::RUST_F32_EPSILON, 0x34000000u); + check_f32(consts::FLOAT_32, 0x3e000000u); + check_f32(consts::FLOAT_32_WHOLE, 0x42800000u); + check_f32(consts::FLOAT_32_NEG_ZERO, 0x80000000u); + check_f32(consts::FLOAT_32_MIN_SUBNORMAL, 0x00000001u); + check_f32(consts::FLOAT_32_MAX_SUBNORMAL, 0x007fffffu); + check_f32(consts::FLOAT_32_NEG_SUBNORMAL, 0x80000001u); + check_f32(consts::FLOAT_32_INFINITY, 0x7f800000u); + check_f32(consts::FLOAT_32_NEG_INFINITY, 0xff800000u); + check_f32(consts::FLOAT_32_NAN, 0x7fc00000u); + check_f32(consts::FLOAT_32_NEG_NAN, 0xffc00000u); + check_f32(consts::FLOAT_32_PAYLOAD_NAN, 0x7fc00042u); + check_f32(consts::FLOAT_32_NEG_PAYLOAD_NAN, 0xffc00042u); + check_f32(consts::FLOAT_32_MAX_PAYLOAD_NAN, 0x7fffffffu); + check_f32(consts::FLOAT_32_SIGNALING_NAN, 0x7f800001u); + check_f32(consts::FLOAT_32_NEG_SIGNALING_NAN, 0xff800001u); + + auto check_f64 = [](double float_value, uint64_t expected_bits) { + SCOPED_TRACE(testing::Message() + << "float_value=" << float_value << ", expected_bits=0x" + << std::hex << expected_bits); + EXPECT_EQ(std::bit_cast(float_value), expected_bits); + EXPECT_EQ(consts::f64_to_bits(float_value), expected_bits); + EXPECT_EQ(std::bit_cast(consts::roundtrip_f64(float_value)), + expected_bits); + }; + check_f64(consts::RUST_F64_MIN, 0xffefffffffffffffull); + check_f64(consts::RUST_F64_MAX, 0x7fefffffffffffffull); + check_f64(consts::RUST_F64_MIN_POSITIVE, 0x0010000000000000ull); + check_f64(consts::RUST_F64_EPSILON, 0x3cb0000000000000ull); + check_f64(consts::FLOAT_64, 0x3f80000000000000ull); + check_f64(consts::FLOAT_64_WHOLE, 0x4050000000000000ull); + check_f64(consts::FLOAT_64_NEG_ZERO, 0x8000000000000000ull); + check_f64(consts::FLOAT_64_MIN_SUBNORMAL, 0x0000000000000001ull); + check_f64(consts::FLOAT_64_MAX_SUBNORMAL, 0x000fffffffffffffull); + check_f64(consts::FLOAT_64_NEG_SUBNORMAL, 0x8000000000000001ull); + check_f64(consts::FLOAT_64_INFINITY, 0x7ff0000000000000ull); + check_f64(consts::FLOAT_64_NEG_INFINITY, 0xfff0000000000000ull); + check_f64(consts::FLOAT_64_NAN, 0x7ff8000000000000ull); + check_f64(consts::FLOAT_64_NEG_NAN, 0xfff8000000000000ull); + check_f64(consts::FLOAT_64_PAYLOAD_NAN, 0x7ff8000000000042ull); + check_f64(consts::FLOAT_64_NEG_PAYLOAD_NAN, 0xfff8000000000042ull); + check_f64(consts::FLOAT_64_MAX_PAYLOAD_NAN, 0x7fffffffffffffffull); + check_f64(consts::FLOAT_64_SIGNALING_NAN, 0x7ff0000000000001ull); + check_f64(consts::FLOAT_64_NEG_SIGNALING_NAN, 0xfff0000000000001ull); +} + } // namespace diff --git a/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api.h b/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api.h index e350c8cce5..125c79fe38 100644 --- a/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api.h +++ b/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api.h @@ -34,11 +34,55 @@ static constexpr ::std::array<::std::int32_t, 3> ARRAY_CONST = ::std::array<::std::int32_t, 3>{INT32_C(10), INT32_C(20), INT32_C(30)}; static constexpr decltype(char(0)) CHAR = 42; static constexpr float FLOAT_32 = 0.125f; +static constexpr float FLOAT_32_INFINITY = __builtin_inff(); +static constexpr float FLOAT_32_MAX_PAYLOAD_NAN = __builtin_nanf("0x3fffff"); +static constexpr float FLOAT_32_MAX_SUBNORMAL = 1.17549421E-38f; +static constexpr float FLOAT_32_MIN_SUBNORMAL = 1.40129846E-45f; +static constexpr float FLOAT_32_NAN = __builtin_nanf(""); +static constexpr float FLOAT_32_NEG_INFINITY = -__builtin_inff(); +static constexpr float FLOAT_32_NEG_NAN = -__builtin_nanf(""); +static constexpr float FLOAT_32_NEG_PAYLOAD_NAN = -__builtin_nanf("0x42"); +static constexpr float FLOAT_32_NEG_SIGNALING_NAN = -__builtin_nansf("0x1"); +static constexpr float FLOAT_32_NEG_SUBNORMAL = -1.40129846E-45f; +static constexpr float FLOAT_32_NEG_ZERO = -0.0f; static constexpr float FLOAT_32_ONE = 1.0f; +static constexpr float FLOAT_32_PAYLOAD_NAN = __builtin_nanf("0x42"); +static constexpr float FLOAT_32_SIGNALING_NAN = __builtin_nansf("0x1"); +static constexpr float FLOAT_32_WHOLE = 64.0f; static constexpr float FLOAT_32_ZERO = 0.0f; -static constexpr double FLOAT_64 = 0.0078125L; -static constexpr double FLOAT_64_ONE = 1.0L; -static constexpr double FLOAT_64_ZERO = 0.0L; +static constexpr double FLOAT_64 = 0.0078125; +static constexpr ::std::array FLOAT_64_ARRAY_CONST = + ::std::array{-0.0, __builtin_inf()}; +static constexpr double FLOAT_64_INFINITY = __builtin_inf(); +static constexpr double FLOAT_64_MAX_PAYLOAD_NAN = + __builtin_nan("0x7ffffffffffff"); +static constexpr double FLOAT_64_MAX_SUBNORMAL = 2.2250738585072009E-308; +static constexpr double FLOAT_64_MIN_SUBNORMAL = 4.9406564584124654E-324; +static constexpr double FLOAT_64_NAN = __builtin_nan(""); +static constexpr double FLOAT_64_NEG_INFINITY = -__builtin_inf(); +static constexpr double FLOAT_64_NEG_NAN = -__builtin_nan(""); +static constexpr double FLOAT_64_NEG_PAYLOAD_NAN = -__builtin_nan("0x42"); +static constexpr double FLOAT_64_NEG_SIGNALING_NAN = -__builtin_nans("0x1"); +static constexpr double FLOAT_64_NEG_SUBNORMAL = -4.9406564584124654E-324; +static constexpr double FLOAT_64_NEG_ZERO = -0.0; +static constexpr double FLOAT_64_ONE = 1.0; +static constexpr double FLOAT_64_PAYLOAD_NAN = __builtin_nan("0x42"); +static constexpr double FLOAT_64_SIGNALING_NAN = __builtin_nans("0x1"); +static constexpr double FLOAT_64_WHOLE = 64.0; +static constexpr double FLOAT_64_ZERO = 0.0; +static constexpr ::std::array FLOAT_ARRAY_CONST = + ::std::array{64.0f, -0.0f, -__builtin_inff(), __builtin_nanf("")}; +struct CRUBIT_INTERNAL_RUST_TYPE(":: consts_golden :: FloatStruct") + [[clang::trivial_abi]] FloatStruct final { + public: + float x{}; + float y{}; + + private: + static void __crubit_field_offset_assertions(); +}; +static constexpr ::consts::FloatStruct FLOAT_STRUCT_CONST = + ::consts::FloatStruct{.x = -0.0f, .y = __builtin_inff()}; static constexpr ::std::int32_t INT_NEG = INT32_C(-17); static constexpr ::std::int32_t INT_POS = INT32_C(42); static constexpr ::std::intptr_t ISIZE = INT64_C(42); @@ -58,10 +102,14 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: consts_golden :: Point") }; static constexpr ::consts::Point POINT_CONST = ::consts::Point{.x = INT32_C(10), .y = INT32_C(-20)}; +static constexpr float RUST_F32_EPSILON = 1.1920929E-7f; static constexpr float RUST_F32_MAX = 3.40282347E+38f; static constexpr float RUST_F32_MIN = -3.40282347E+38f; -static constexpr double RUST_F64_MAX = 1.7976931348623157E+308L; -static constexpr double RUST_F64_MIN = -1.7976931348623157E+308L; +static constexpr float RUST_F32_MIN_POSITIVE = 1.17549435E-38f; +static constexpr double RUST_F64_EPSILON = 2.2204460492503131E-16; +static constexpr double RUST_F64_MAX = 1.7976931348623157E+308; +static constexpr double RUST_F64_MIN = -1.7976931348623157E+308; +static constexpr double RUST_F64_MIN_POSITIVE = 2.2250738585072014E-308; static constexpr bool RUST_FALSE = false; static constexpr ::std::int16_t RUST_INT16_MAX = 32767; static constexpr ::std::int16_t RUST_INT16_MIN = -32768; @@ -207,12 +255,35 @@ TyWithAssocConsts final { }; static constexpr ::std::uint32_t UNSIGNED_INT = UINT32_C(4294967295); +// CRUBIT_ANNOTATE: must_bind= +::std::uint32_t f32_to_bits(float x); + +// CRUBIT_ANNOTATE: must_bind= +::std::uint64_t f64_to_bits(double x); + // Error generating bindings for function // `consts_golden::fn_with_unreturnable_const`: Function contains a const block // that cannot return +// CRUBIT_ANNOTATE: must_bind= +float roundtrip_f32(float x); + +// CRUBIT_ANNOTATE: must_bind= +double roundtrip_f64(double x); + } // namespace consts +template <> +struct ::rs::impl<::consts::FloatStruct, ::rs::core::fmt::Debug> { + static constexpr bool kIsImplemented = true; + + // Error generating bindings for associated function + // `::fmt`: Error formatting + // function return type `std::result::Result<(), std::fmt::Error>`: Failed to + // format type for the definition of `std::fmt::Error`: Zero-sized types + // (ZSTs) are not supported (b/258259459) +}; + template <> struct ::rs::impl<::consts::NestedStruct, ::rs::core::cmp::Eq> { static constexpr bool kIsImplemented = true; @@ -311,6 +382,22 @@ struct ::rs::impl<::consts::TupleStruct, ::rs::core::fmt::Debug> { namespace consts { +static_assert( + sizeof(::consts::FloatStruct) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(::consts::FloatStruct) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_move_constructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_move_assignable_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_copy_constructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_copy_assignable_v<::consts::FloatStruct>); +inline void ::consts::FloatStruct::__crubit_field_offset_assertions() { + using __crubit_assert_type = ::consts::FloatStruct; + static_assert(0 == offsetof(__crubit_assert_type, x)); + static_assert(4 == offsetof(__crubit_assert_type, y)); +} static_assert( sizeof(::consts::NestedStruct) == 16, "Verify that ADT layout didn't change since this header got generated"); @@ -507,6 +594,34 @@ inline void ::consts::TyWithAssocConsts::__crubit_field_offset_assertions() { using __crubit_assert_type = ::consts::TyWithAssocConsts; static_assert(0 == offsetof(__crubit_assert_type, __field0)); } +namespace __crubit_internal { +extern "C" ::std::uint32_t __crubit_thunk_f32_uto_ubits(float); +} +inline ::std::uint32_t f32_to_bits(float x) { + return __crubit_internal::__crubit_thunk_f32_uto_ubits(x); +} + +namespace __crubit_internal { +extern "C" ::std::uint64_t __crubit_thunk_f64_uto_ubits(double); +} +inline ::std::uint64_t f64_to_bits(double x) { + return __crubit_internal::__crubit_thunk_f64_uto_ubits(x); +} + +namespace __crubit_internal { +extern "C" float __crubit_thunk_roundtrip_uf32(float); +} +inline float roundtrip_f32(float x) { + return __crubit_internal::__crubit_thunk_roundtrip_uf32(x); +} + +namespace __crubit_internal { +extern "C" double __crubit_thunk_roundtrip_uf64(double); +} +inline double roundtrip_f64(double x) { + return __crubit_internal::__crubit_thunk_roundtrip_uf64(x); +} + } // namespace consts #pragma clang diagnostic pop diff --git a/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api_impl.rs b/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api_impl.rs index 56cf5315e2..0ffeb6034e 100644 --- a/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/consts/goldens/android_32/consts_cc_api_impl.rs @@ -11,6 +11,10 @@ extern crate alloc; extern crate core; +const _: () = assert!(::core::mem::size_of::<::consts_golden::FloatStruct>() == 8); +const _: () = assert!(::core::mem::align_of::<::consts_golden::FloatStruct>() == 4); +const _: () = assert!(::core::mem::offset_of!(::consts_golden::FloatStruct, x) == 0); +const _: () = assert!(::core::mem::offset_of!(::consts_golden::FloatStruct, y) == 4); const _: () = assert!(::core::mem::size_of::<::consts_golden::NestedStruct>() == 16); const _: () = assert!(::core::mem::align_of::<::consts_golden::NestedStruct>() == 4); #[unsafe(no_mangle)] @@ -101,3 +105,19 @@ const _: () = assert!(::core::mem::offset_of!(::consts_golden::TupleStruct, 0) = const _: () = assert!(::core::mem::offset_of!(::consts_golden::TupleStruct, 1) == 4); const _: () = assert!(::core::mem::size_of::<::consts_golden::TyWithAssocConsts>() == 1); const _: () = assert!(::core::mem::align_of::<::consts_golden::TyWithAssocConsts>() == 1); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_f32_uto_ubits(x: f32) -> u32 { + unsafe { ::consts_golden::f32_to_bits(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_f64_uto_ubits(x: f64) -> u64 { + unsafe { ::consts_golden::f64_to_bits(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_roundtrip_uf32(x: f32) -> f32 { + unsafe { ::consts_golden::roundtrip_f32(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_roundtrip_uf64(x: f64) -> f64 { + unsafe { ::consts_golden::roundtrip_f64(x) } +} diff --git a/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api.h b/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api.h index e350c8cce5..125c79fe38 100644 --- a/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api.h +++ b/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api.h @@ -34,11 +34,55 @@ static constexpr ::std::array<::std::int32_t, 3> ARRAY_CONST = ::std::array<::std::int32_t, 3>{INT32_C(10), INT32_C(20), INT32_C(30)}; static constexpr decltype(char(0)) CHAR = 42; static constexpr float FLOAT_32 = 0.125f; +static constexpr float FLOAT_32_INFINITY = __builtin_inff(); +static constexpr float FLOAT_32_MAX_PAYLOAD_NAN = __builtin_nanf("0x3fffff"); +static constexpr float FLOAT_32_MAX_SUBNORMAL = 1.17549421E-38f; +static constexpr float FLOAT_32_MIN_SUBNORMAL = 1.40129846E-45f; +static constexpr float FLOAT_32_NAN = __builtin_nanf(""); +static constexpr float FLOAT_32_NEG_INFINITY = -__builtin_inff(); +static constexpr float FLOAT_32_NEG_NAN = -__builtin_nanf(""); +static constexpr float FLOAT_32_NEG_PAYLOAD_NAN = -__builtin_nanf("0x42"); +static constexpr float FLOAT_32_NEG_SIGNALING_NAN = -__builtin_nansf("0x1"); +static constexpr float FLOAT_32_NEG_SUBNORMAL = -1.40129846E-45f; +static constexpr float FLOAT_32_NEG_ZERO = -0.0f; static constexpr float FLOAT_32_ONE = 1.0f; +static constexpr float FLOAT_32_PAYLOAD_NAN = __builtin_nanf("0x42"); +static constexpr float FLOAT_32_SIGNALING_NAN = __builtin_nansf("0x1"); +static constexpr float FLOAT_32_WHOLE = 64.0f; static constexpr float FLOAT_32_ZERO = 0.0f; -static constexpr double FLOAT_64 = 0.0078125L; -static constexpr double FLOAT_64_ONE = 1.0L; -static constexpr double FLOAT_64_ZERO = 0.0L; +static constexpr double FLOAT_64 = 0.0078125; +static constexpr ::std::array FLOAT_64_ARRAY_CONST = + ::std::array{-0.0, __builtin_inf()}; +static constexpr double FLOAT_64_INFINITY = __builtin_inf(); +static constexpr double FLOAT_64_MAX_PAYLOAD_NAN = + __builtin_nan("0x7ffffffffffff"); +static constexpr double FLOAT_64_MAX_SUBNORMAL = 2.2250738585072009E-308; +static constexpr double FLOAT_64_MIN_SUBNORMAL = 4.9406564584124654E-324; +static constexpr double FLOAT_64_NAN = __builtin_nan(""); +static constexpr double FLOAT_64_NEG_INFINITY = -__builtin_inf(); +static constexpr double FLOAT_64_NEG_NAN = -__builtin_nan(""); +static constexpr double FLOAT_64_NEG_PAYLOAD_NAN = -__builtin_nan("0x42"); +static constexpr double FLOAT_64_NEG_SIGNALING_NAN = -__builtin_nans("0x1"); +static constexpr double FLOAT_64_NEG_SUBNORMAL = -4.9406564584124654E-324; +static constexpr double FLOAT_64_NEG_ZERO = -0.0; +static constexpr double FLOAT_64_ONE = 1.0; +static constexpr double FLOAT_64_PAYLOAD_NAN = __builtin_nan("0x42"); +static constexpr double FLOAT_64_SIGNALING_NAN = __builtin_nans("0x1"); +static constexpr double FLOAT_64_WHOLE = 64.0; +static constexpr double FLOAT_64_ZERO = 0.0; +static constexpr ::std::array FLOAT_ARRAY_CONST = + ::std::array{64.0f, -0.0f, -__builtin_inff(), __builtin_nanf("")}; +struct CRUBIT_INTERNAL_RUST_TYPE(":: consts_golden :: FloatStruct") + [[clang::trivial_abi]] FloatStruct final { + public: + float x{}; + float y{}; + + private: + static void __crubit_field_offset_assertions(); +}; +static constexpr ::consts::FloatStruct FLOAT_STRUCT_CONST = + ::consts::FloatStruct{.x = -0.0f, .y = __builtin_inff()}; static constexpr ::std::int32_t INT_NEG = INT32_C(-17); static constexpr ::std::int32_t INT_POS = INT32_C(42); static constexpr ::std::intptr_t ISIZE = INT64_C(42); @@ -58,10 +102,14 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: consts_golden :: Point") }; static constexpr ::consts::Point POINT_CONST = ::consts::Point{.x = INT32_C(10), .y = INT32_C(-20)}; +static constexpr float RUST_F32_EPSILON = 1.1920929E-7f; static constexpr float RUST_F32_MAX = 3.40282347E+38f; static constexpr float RUST_F32_MIN = -3.40282347E+38f; -static constexpr double RUST_F64_MAX = 1.7976931348623157E+308L; -static constexpr double RUST_F64_MIN = -1.7976931348623157E+308L; +static constexpr float RUST_F32_MIN_POSITIVE = 1.17549435E-38f; +static constexpr double RUST_F64_EPSILON = 2.2204460492503131E-16; +static constexpr double RUST_F64_MAX = 1.7976931348623157E+308; +static constexpr double RUST_F64_MIN = -1.7976931348623157E+308; +static constexpr double RUST_F64_MIN_POSITIVE = 2.2250738585072014E-308; static constexpr bool RUST_FALSE = false; static constexpr ::std::int16_t RUST_INT16_MAX = 32767; static constexpr ::std::int16_t RUST_INT16_MIN = -32768; @@ -207,12 +255,35 @@ TyWithAssocConsts final { }; static constexpr ::std::uint32_t UNSIGNED_INT = UINT32_C(4294967295); +// CRUBIT_ANNOTATE: must_bind= +::std::uint32_t f32_to_bits(float x); + +// CRUBIT_ANNOTATE: must_bind= +::std::uint64_t f64_to_bits(double x); + // Error generating bindings for function // `consts_golden::fn_with_unreturnable_const`: Function contains a const block // that cannot return +// CRUBIT_ANNOTATE: must_bind= +float roundtrip_f32(float x); + +// CRUBIT_ANNOTATE: must_bind= +double roundtrip_f64(double x); + } // namespace consts +template <> +struct ::rs::impl<::consts::FloatStruct, ::rs::core::fmt::Debug> { + static constexpr bool kIsImplemented = true; + + // Error generating bindings for associated function + // `::fmt`: Error formatting + // function return type `std::result::Result<(), std::fmt::Error>`: Failed to + // format type for the definition of `std::fmt::Error`: Zero-sized types + // (ZSTs) are not supported (b/258259459) +}; + template <> struct ::rs::impl<::consts::NestedStruct, ::rs::core::cmp::Eq> { static constexpr bool kIsImplemented = true; @@ -311,6 +382,22 @@ struct ::rs::impl<::consts::TupleStruct, ::rs::core::fmt::Debug> { namespace consts { +static_assert( + sizeof(::consts::FloatStruct) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(::consts::FloatStruct) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_move_constructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_move_assignable_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_copy_constructible_v<::consts::FloatStruct>); +static_assert(::std::is_trivially_copy_assignable_v<::consts::FloatStruct>); +inline void ::consts::FloatStruct::__crubit_field_offset_assertions() { + using __crubit_assert_type = ::consts::FloatStruct; + static_assert(0 == offsetof(__crubit_assert_type, x)); + static_assert(4 == offsetof(__crubit_assert_type, y)); +} static_assert( sizeof(::consts::NestedStruct) == 16, "Verify that ADT layout didn't change since this header got generated"); @@ -507,6 +594,34 @@ inline void ::consts::TyWithAssocConsts::__crubit_field_offset_assertions() { using __crubit_assert_type = ::consts::TyWithAssocConsts; static_assert(0 == offsetof(__crubit_assert_type, __field0)); } +namespace __crubit_internal { +extern "C" ::std::uint32_t __crubit_thunk_f32_uto_ubits(float); +} +inline ::std::uint32_t f32_to_bits(float x) { + return __crubit_internal::__crubit_thunk_f32_uto_ubits(x); +} + +namespace __crubit_internal { +extern "C" ::std::uint64_t __crubit_thunk_f64_uto_ubits(double); +} +inline ::std::uint64_t f64_to_bits(double x) { + return __crubit_internal::__crubit_thunk_f64_uto_ubits(x); +} + +namespace __crubit_internal { +extern "C" float __crubit_thunk_roundtrip_uf32(float); +} +inline float roundtrip_f32(float x) { + return __crubit_internal::__crubit_thunk_roundtrip_uf32(x); +} + +namespace __crubit_internal { +extern "C" double __crubit_thunk_roundtrip_uf64(double); +} +inline double roundtrip_f64(double x) { + return __crubit_internal::__crubit_thunk_roundtrip_uf64(x); +} + } // namespace consts #pragma clang diagnostic pop diff --git a/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api_impl.rs b/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api_impl.rs index 56cf5315e2..0ffeb6034e 100644 --- a/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/consts/goldens/windows_32/consts_cc_api_impl.rs @@ -11,6 +11,10 @@ extern crate alloc; extern crate core; +const _: () = assert!(::core::mem::size_of::<::consts_golden::FloatStruct>() == 8); +const _: () = assert!(::core::mem::align_of::<::consts_golden::FloatStruct>() == 4); +const _: () = assert!(::core::mem::offset_of!(::consts_golden::FloatStruct, x) == 0); +const _: () = assert!(::core::mem::offset_of!(::consts_golden::FloatStruct, y) == 4); const _: () = assert!(::core::mem::size_of::<::consts_golden::NestedStruct>() == 16); const _: () = assert!(::core::mem::align_of::<::consts_golden::NestedStruct>() == 4); #[unsafe(no_mangle)] @@ -101,3 +105,19 @@ const _: () = assert!(::core::mem::offset_of!(::consts_golden::TupleStruct, 0) = const _: () = assert!(::core::mem::offset_of!(::consts_golden::TupleStruct, 1) == 4); const _: () = assert!(::core::mem::size_of::<::consts_golden::TyWithAssocConsts>() == 1); const _: () = assert!(::core::mem::align_of::<::consts_golden::TyWithAssocConsts>() == 1); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_f32_uto_ubits(x: f32) -> u32 { + unsafe { ::consts_golden::f32_to_bits(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_f64_uto_ubits(x: f64) -> u64 { + unsafe { ::consts_golden::f64_to_bits(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_roundtrip_uf32(x: f32) -> f32 { + unsafe { ::consts_golden::roundtrip_f32(x) } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_roundtrip_uf64(x: f64) -> f64 { + unsafe { ::consts_golden::roundtrip_f64(x) } +}