Skip to content

Add cfg(no_128_bit) to core: removes u128/i128 formatting #103126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 1 addition & 1 deletion library/core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ description = "The Rust Core Library"
autotests = false
autobenches = false
# If you update this, be sure to update it in a bunch of other places too!
# As of 2022, it was the ci/pgo.sh script and the core-no-fp-fmt-parse test.
# As of 2023, it was the ci/pgo.sh script and the core-no-fp-fmt-parse/core-no-128-bit tests.
edition = "2021"

[lib]
38 changes: 35 additions & 3 deletions library/core/src/fmt/num.rs
Original file line number Diff line number Diff line change
@@ -176,9 +176,12 @@ integer! { i8, u8 }
integer! { i16, u16 }
integer! { i32, u32 }
integer! { i64, u64 }
#[cfg(not(no_128_bit))]
integer! { i128, u128 }

macro_rules! debug {
($($T:ident)*) => {$(
($($( #[$cfg:meta] )? $T:ident)*) => {$(
$( #[$cfg] )?
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for $T {
#[inline]
@@ -195,8 +198,30 @@ macro_rules! debug {
)*};
}
debug! {
i8 i16 i32 i64 i128 isize
u8 u16 u32 u64 u128 usize
i8 i16 i32 i64 #[cfg(not(no_128_bit))] i128 isize
u8 u16 u32 u64 #[cfg(not(no_128_bit))] u128 usize
}

macro_rules! fake_debug {
($($( #[$cfg:meta] )? $T:ident)*) => {$(
$( #[$cfg] )?
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for $T {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Debug formats are not stable so this is a legitimate implementation.
// It would be possible to hexdump the contents instead, or to
// fail or panic, but for an application which has specifically
// recompiled core to avoid i128, the former seems unnecessary
// and the latter needlessly harmful.
f.write_str(stringify!($T))
Copy link
Member

Choose a reason for hiding this comment

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

Why is an i128/u128 impl necessary in the first place?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question; I haven’t tried removing it. I think it’s conventional to provide Debug for everything public in the standard library; not sure if that could be waived in this case?

}
}
)*}
}
fake_debug! {
#[cfg(no_128_bit)] i128
#[cfg(no_128_bit)] u128
}

// 2 digit decimal look up table
@@ -476,9 +501,11 @@ mod imp {
impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32);
impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64);
}
#[cfg(not(no_128_bit))]
impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);

/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
#[cfg(not(no_128_bit))] // unused for `no_128_bit`
fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize) {
let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf);
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
@@ -566,13 +593,15 @@ fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], cu
}

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(no_128_bit))]
impl fmt::Display for u128 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt_u128(*self, true, f)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(no_128_bit))]
impl fmt::Display for i128 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let is_nonnegative = *self >= 0;
@@ -590,6 +619,7 @@ impl fmt::Display for i128 {
/// into at most 2 u64s, and then chunks by 10e16, 10e8, 10e4, 10e2, and then 10e1.
/// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas
/// 10^20 > 2^64 > 10^19.
#[cfg(not(no_128_bit))]
fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// 2^128 is about 3*10^38, so 39 gives an extra byte of space
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
@@ -649,6 +679,7 @@ fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::R
/// in Proc. of the SIGPLAN94 Conference on Programming Language Design and
/// Implementation, 1994, pp. 61–72
///
#[cfg(not(no_128_bit))]
fn udiv_1e19(n: u128) -> (u128, u64) {
const DIV: u64 = 1e19 as u64;
const FACTOR: u128 = 156927543384667019095894735580191660403;
@@ -665,6 +696,7 @@ fn udiv_1e19(n: u128) -> (u128, u64) {

/// Multiply unsigned 128 bit integers, return upper 128 bits of the result
#[inline]
#[cfg(not(no_128_bit))]
fn u128_mulhi(x: u128, y: u128) -> u128 {
let x_lo = x as u64;
let x_hi = (x >> 64) as u64;
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@
not(test),
any(not(feature = "miri-test-libstd"), test, doctest),
no_fp_fmt_parse,
no_128_bit,
target_pointer_width = "16",
target_pointer_width = "32",
target_pointer_width = "64",
3 changes: 2 additions & 1 deletion library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ macro_rules! int_impl {
$rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr,
$bound_condition:expr) => {
$bound_condition:expr $(, #[$intrinsics_cfg:meta])?) => {
/// The smallest value that can be represented by this integer type
#[doc = concat!("(&minus;2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ")")]
///
@@ -62,6 +62,7 @@ macro_rules! int_impl {
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
$( #[$intrinsics_cfg] )?
Copy link
Member

Choose a reason for hiding this comment

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

This is doing more than just controlling the removal of formatting: this function is about parsing. If not called, the function should not be included by the linker, different to what's happening to stuff called by the fmt machinery that is always included the moment anything that uses the fmt machinery is included.

pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
from_str_radix(src, radix)
}
12 changes: 8 additions & 4 deletions library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
@@ -268,7 +268,7 @@ impl i128 {
"[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "", "" }
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "", "", #[cfg(not(no_128_bit))] }
}

#[cfg(target_pointer_width = "16")]
@@ -940,7 +940,7 @@ impl u128 {
0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]",
"", "", ""}
"", "", "", #[cfg(not(no_128_bit))]}
}

#[cfg(target_pointer_width = "16")]
@@ -1078,7 +1078,9 @@ macro_rules! from_str_radix_int_impl {
}
)*}
}
from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 }
#[cfg(not(no_128_bit))]
from_str_radix_int_impl! { i128 u128 }

macro_rules! impl_helper_for {
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
@@ -1099,7 +1101,9 @@ macro_rules! impl_helper_for {
}
})*)
}
impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
impl_helper_for! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
#[cfg(not(no_128_bit))]
impl_helper_for! { i128 u128 }

/// Determines if a string of text of that length of that radix could be guaranteed to be
/// stored in the given type T.
20 changes: 14 additions & 6 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ macro_rules! impl_nonzero_fmt {
}

macro_rules! nonzero_integers {
( $( #[$stability: meta] #[$const_new_unchecked_stability: meta] $Ty: ident($Int: ty); )+ ) => {
( $( #[$stability: meta] #[$const_new_unchecked_stability: meta] $(#[$cfg: meta])? $Ty: ident($Int: ty); )+ ) => {
$(
/// An integer that is known not to equal zero.
///
@@ -154,9 +154,12 @@ macro_rules! nonzero_integers {
}
}

$(#[$cfg])?
impl_nonzero_fmt! {
#[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
#[$stability] (Display, Binary, Octal, LowerHex, UpperHex) for $Ty
}

impl_nonzero_fmt!(#[$stability] (Debug) for $Ty);
)+
}
}
@@ -166,13 +169,15 @@ nonzero_integers! {
#[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16);
#[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32);
#[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64);
#[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128);
#[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")]
#[cfg(not(no_128_bit))] NonZeroU128(u128);
Copy link
Member

Choose a reason for hiding this comment

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

Same here, I don't think it should be cfg'd out in this PR.

#[stable(feature = "nonzero", since = "1.28.0")] #[rustc_const_stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize);
#[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8);
#[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16);
#[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32);
#[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64);
#[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128);
#[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")]
#[cfg(not(no_128_bit))] NonZeroI128(i128);
#[stable(feature = "signed_nonzero", since = "1.34.0")] #[rustc_const_stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
}

@@ -191,8 +196,11 @@ macro_rules! from_str_radix_nzint_impl {
)*}
}

from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroUsize
NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroIsize }

#[cfg(not(no_128_bit))]
from_str_radix_nzint_impl! { NonZeroU128 NonZeroI128 }

macro_rules! nonzero_leading_trailing_zeros {
( $( $Ty: ident($Uint: ty) , $LeadingTestExpr:expr ;)+ ) => {
3 changes: 2 additions & 1 deletion library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ macro_rules! uint_impl {
$rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
$reversed:expr, $le_bytes:expr, $be_bytes:expr,
$to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr,
$bound_condition:expr) => {
$bound_condition:expr $(, #[$intrinsics_cfg:meta])?) => {
/// The smallest value that can be represented by this integer type.
///
/// # Examples
@@ -63,6 +63,7 @@ macro_rules! uint_impl {
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));")]
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
$( #[$intrinsics_cfg] )?
pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
from_str_radix(src, radix)
}
1 change: 1 addition & 0 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
@@ -207,6 +207,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
(Some(Mode::Codegen), "parallel_compiler", None),
(Some(Mode::Std), "stdarch_intel_sde", None),
(Some(Mode::Std), "no_fp_fmt_parse", None),
(Some(Mode::Std), "no_128_bit", None),
(Some(Mode::Std), "no_global_oom_handling", None),
(Some(Mode::Std), "no_rc", None),
(Some(Mode::Std), "no_sync", None),
8 changes: 8 additions & 0 deletions tests/run-make-fulldeps/core-no-128-bit/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include ../tools.mk

all:
$(RUSTC) --edition=2021 --crate-type=rlib --crate-name=core ../../../library/core/src/lib.rs --cfg no_128_bit
$(RUSTC) --edition=2021 --crate-type=staticlib --crate-name=demo --sysroot=. -C panic=abort lib.rs
# Expect that objdump succeeds and grep fails. The grep pattern is for names like __multi3.
# There is no pipefail on dash so echo a string that will fail the test if objump fails.
(objdump -t $(TMPDIR)/libdemo.a || echo __objdumpfailedti) | (! grep -w '__[a-z]\+ti[0-9]\?')
31 changes: 31 additions & 0 deletions tests/run-make-fulldeps/core-no-128-bit/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#![feature(no_core)]

#![no_std]
#![no_core] // supress compiler-builtins
extern crate core;
use core::prelude::rust_2021::*;
use core::fmt::Write;

// An empty file might be sufficient here, but since formatting is one of the
// features affected by no_128_bit it seems worth including some.

struct X(pub usize);
impl core::fmt::Write for X {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.0 += s.len();
Ok(())
}
}

#[no_mangle]
extern "C" fn demo() -> usize {
let mut x = X(0);
// Writes "i128 u128 foo" due to the removal of u/i128 formatting.
core::write!(x, "{:?} {:?} {}", i128::MAX, u128::MIN, "foo").unwrap();
x.0
}

#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}