From 37647d1733c368dfb4a81f368cefa09adf6bf20d Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Sun, 6 Jun 2021 02:08:09 +0100
Subject: [PATCH 1/2] Move `flt2dec::{Formatted, Part}` to dedicated module

They are used by integer formatting as well and is not exclusive to float.
---
 library/core/src/fmt/float.rs         |   9 ++-
 library/core/src/fmt/mod.rs           |  20 ++---
 library/core/src/fmt/num.rs           |  10 +--
 library/core/src/num/flt2dec/mod.rs   | 102 +-----------------------
 library/core/src/num/fmt.rs           | 108 ++++++++++++++++++++++++++
 library/core/src/num/mod.rs           |   1 +
 library/core/tests/lib.rs             |   1 +
 library/core/tests/num/flt2dec/mod.rs |   3 +-
 8 files changed, 133 insertions(+), 121 deletions(-)
 create mode 100644 library/core/src/num/fmt.rs

diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs
index ece3cde001580..ba65f0fadbd9d 100644
--- a/library/core/src/fmt/float.rs
+++ b/library/core/src/fmt/float.rs
@@ -1,6 +1,7 @@
 use crate::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp};
 use crate::mem::MaybeUninit;
 use crate::num::flt2dec;
+use crate::num::fmt as numfmt;
 
 // Don't inline this so callers don't use the stack space this function
 // requires unless they have to.
@@ -15,7 +16,7 @@ where
     T: flt2dec::DecodableFloat,
 {
     let mut buf: [MaybeUninit<u8>; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64
-    let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 4] = MaybeUninit::uninit_array();
+    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = MaybeUninit::uninit_array();
     let formatted = flt2dec::to_exact_fixed_str(
         flt2dec::strategy::grisu::format_exact,
         *num,
@@ -41,7 +42,7 @@ where
 {
     // enough for f32 and f64
     let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array();
-    let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 4] = MaybeUninit::uninit_array();
+    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = MaybeUninit::uninit_array();
     let formatted = flt2dec::to_shortest_str(
         flt2dec::strategy::grisu::format_shortest,
         *num,
@@ -85,7 +86,7 @@ where
     T: flt2dec::DecodableFloat,
 {
     let mut buf: [MaybeUninit<u8>; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64
-    let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 6] = MaybeUninit::uninit_array();
+    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = MaybeUninit::uninit_array();
     let formatted = flt2dec::to_exact_exp_str(
         flt2dec::strategy::grisu::format_exact,
         *num,
@@ -112,7 +113,7 @@ where
 {
     // enough for f32 and f64
     let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array();
-    let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 6] = MaybeUninit::uninit_array();
+    let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = MaybeUninit::uninit_array();
     let formatted = flt2dec::to_shortest_exp_str(
         flt2dec::strategy::grisu::format_shortest,
         *num,
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 02ac4fb800655..1adfb73ced04d 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -7,7 +7,7 @@ use crate::char::EscapeDebugExtArgs;
 use crate::iter;
 use crate::marker::PhantomData;
 use crate::mem;
-use crate::num::flt2dec;
+use crate::num::fmt as numfmt;
 use crate::ops::Deref;
 use crate::result;
 use crate::str;
@@ -1421,7 +1421,7 @@ impl<'a> Formatter<'a> {
     /// Takes the formatted parts and applies the padding.
     /// Assumes that the caller already has rendered the parts with required precision,
     /// so that `self.precision` can be ignored.
-    fn pad_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result {
+    fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
         if let Some(mut width) = self.width {
             // for the sign-aware zero padding, we render the sign first and
             // behave as if we had no sign from the beginning.
@@ -1461,14 +1461,14 @@ impl<'a> Formatter<'a> {
         }
     }
 
-    fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result {
+    fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
         fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
-            // SAFETY: This is used for `flt2dec::Part::Num` and `flt2dec::Part::Copy`.
-            // It's safe to use for `flt2dec::Part::Num` since every char `c` is between
+            // SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`.
+            // It's safe to use for `numfmt::Part::Num` since every char `c` is between
             // `b'0'` and `b'9'`, which means `s` is valid UTF-8.
-            // It's also probably safe in practice to use for `flt2dec::Part::Copy(buf)`
+            // It's also probably safe in practice to use for `numfmt::Part::Copy(buf)`
             // since `buf` should be plain ASCII, but it's possible for someone to pass
-            // in a bad value for `buf` into `flt2dec::to_shortest_str` since it is a
+            // in a bad value for `buf` into `numfmt::to_shortest_str` since it is a
             // public function.
             // FIXME: Determine whether this could result in UB.
             buf.write_str(unsafe { str::from_utf8_unchecked(s) })
@@ -1479,7 +1479,7 @@ impl<'a> Formatter<'a> {
         }
         for part in formatted.parts {
             match *part {
-                flt2dec::Part::Zero(mut nzeroes) => {
+                numfmt::Part::Zero(mut nzeroes) => {
                     const ZEROES: &str = // 64 zeroes
                         "0000000000000000000000000000000000000000000000000000000000000000";
                     while nzeroes > ZEROES.len() {
@@ -1490,7 +1490,7 @@ impl<'a> Formatter<'a> {
                         self.buf.write_str(&ZEROES[..nzeroes])?;
                     }
                 }
-                flt2dec::Part::Num(mut v) => {
+                numfmt::Part::Num(mut v) => {
                     let mut s = [0; 5];
                     let len = part.len();
                     for c in s[..len].iter_mut().rev() {
@@ -1499,7 +1499,7 @@ impl<'a> Formatter<'a> {
                     }
                     write_bytes(self.buf, &s[..len])?;
                 }
-                flt2dec::Part::Copy(buf) => {
+                numfmt::Part::Copy(buf) => {
                     write_bytes(self.buf, buf)?;
                 }
             }
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index cdd731fdd4d4e..db45640df48d6 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -2,7 +2,7 @@
 
 use crate::fmt;
 use crate::mem::MaybeUninit;
-use crate::num::flt2dec;
+use crate::num::fmt as numfmt;
 use crate::ops::{Div, Rem, Sub};
 use crate::ptr;
 use crate::slice;
@@ -406,9 +406,9 @@ macro_rules! impl_Exp {
             };
 
             let parts = &[
-                flt2dec::Part::Copy(buf_slice),
-                flt2dec::Part::Zero(added_precision),
-                flt2dec::Part::Copy(exp_slice)
+                numfmt::Part::Copy(buf_slice),
+                numfmt::Part::Zero(added_precision),
+                numfmt::Part::Copy(exp_slice)
             ];
             let sign = if !is_nonnegative {
                 "-"
@@ -417,7 +417,7 @@ macro_rules! impl_Exp {
             } else {
                 ""
             };
-            let formatted = flt2dec::Formatted{sign, parts};
+            let formatted = numfmt::Formatted{sign, parts};
             f.pad_formatted_parts(&formatted)
         }
 
diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/flt2dec/mod.rs
index 93bdf5040e08b..62ae30e9ad386 100644
--- a/library/core/src/num/flt2dec/mod.rs
+++ b/library/core/src/num/flt2dec/mod.rs
@@ -124,6 +124,7 @@ functions.
 
 pub use self::decoder::{decode, DecodableFloat, Decoded, FullDecoded};
 
+use super::fmt::{Formatted, Part};
 use crate::mem::MaybeUninit;
 
 pub mod decoder;
@@ -170,107 +171,6 @@ pub fn round_up(d: &mut [u8]) -> Option<u8> {
     }
 }
 
-/// Formatted parts.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Part<'a> {
-    /// Given number of zero digits.
-    Zero(usize),
-    /// A literal number up to 5 digits.
-    Num(u16),
-    /// A verbatim copy of given bytes.
-    Copy(&'a [u8]),
-}
-
-impl<'a> Part<'a> {
-    /// Returns the exact byte length of given part.
-    pub fn len(&self) -> usize {
-        match *self {
-            Part::Zero(nzeroes) => nzeroes,
-            Part::Num(v) => {
-                if v < 1_000 {
-                    if v < 10 {
-                        1
-                    } else if v < 100 {
-                        2
-                    } else {
-                        3
-                    }
-                } else {
-                    if v < 10_000 { 4 } else { 5 }
-                }
-            }
-            Part::Copy(buf) => buf.len(),
-        }
-    }
-
-    /// Writes a part into the supplied buffer.
-    /// Returns the number of written bytes, or `None` if the buffer is not enough.
-    /// (It may still leave partially written bytes in the buffer; do not rely on that.)
-    pub fn write(&self, out: &mut [u8]) -> Option<usize> {
-        let len = self.len();
-        if out.len() >= len {
-            match *self {
-                Part::Zero(nzeroes) => {
-                    for c in &mut out[..nzeroes] {
-                        *c = b'0';
-                    }
-                }
-                Part::Num(mut v) => {
-                    for c in out[..len].iter_mut().rev() {
-                        *c = b'0' + (v % 10) as u8;
-                        v /= 10;
-                    }
-                }
-                Part::Copy(buf) => {
-                    out[..buf.len()].copy_from_slice(buf);
-                }
-            }
-            Some(len)
-        } else {
-            None
-        }
-    }
-}
-
-/// Formatted result containing one or more parts.
-/// This can be written to the byte buffer or converted to the allocated string.
-#[allow(missing_debug_implementations)]
-#[derive(Clone)]
-pub struct Formatted<'a> {
-    /// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
-    pub sign: &'static str,
-    /// Formatted parts to be rendered after a sign and optional zero padding.
-    pub parts: &'a [Part<'a>],
-}
-
-impl<'a> Formatted<'a> {
-    /// Returns the exact byte length of combined formatted result.
-    pub fn len(&self) -> usize {
-        let mut len = self.sign.len();
-        for part in self.parts {
-            len += part.len();
-        }
-        len
-    }
-
-    /// Writes all formatted parts into the supplied buffer.
-    /// Returns the number of written bytes, or `None` if the buffer is not enough.
-    /// (It may still leave partially written bytes in the buffer; do not rely on that.)
-    pub fn write(&self, out: &mut [u8]) -> Option<usize> {
-        if out.len() < self.sign.len() {
-            return None;
-        }
-        out[..self.sign.len()].copy_from_slice(self.sign.as_bytes());
-
-        let mut written = self.sign.len();
-        for part in self.parts {
-            let len = part.write(&mut out[written..])?;
-            written += len;
-        }
-        Some(written)
-    }
-}
-
 /// Formats given decimal digits `0.<...buf...> * 10^exp` into the decimal form
 /// with at least given number of fractional digits. The result is stored to
 /// the supplied parts array and a slice of written parts is returned.
diff --git a/library/core/src/num/fmt.rs b/library/core/src/num/fmt.rs
new file mode 100644
index 0000000000000..578288bda2595
--- /dev/null
+++ b/library/core/src/num/fmt.rs
@@ -0,0 +1,108 @@
+//! Shared utilties used by both float and integer formatting.
+#![doc(hidden)]
+#![unstable(
+    feature = "numfmt",
+    reason = "internal routines only exposed for testing",
+    issue = "none"
+)]
+
+/// Formatted parts.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Part<'a> {
+    /// Given number of zero digits.
+    Zero(usize),
+    /// A literal number up to 5 digits.
+    Num(u16),
+    /// A verbatim copy of given bytes.
+    Copy(&'a [u8]),
+}
+
+impl<'a> Part<'a> {
+    /// Returns the exact byte length of given part.
+    pub fn len(&self) -> usize {
+        match *self {
+            Part::Zero(nzeroes) => nzeroes,
+            Part::Num(v) => {
+                if v < 1_000 {
+                    if v < 10 {
+                        1
+                    } else if v < 100 {
+                        2
+                    } else {
+                        3
+                    }
+                } else {
+                    if v < 10_000 { 4 } else { 5 }
+                }
+            }
+            Part::Copy(buf) => buf.len(),
+        }
+    }
+
+    /// Writes a part into the supplied buffer.
+    /// Returns the number of written bytes, or `None` if the buffer is not enough.
+    /// (It may still leave partially written bytes in the buffer; do not rely on that.)
+    pub fn write(&self, out: &mut [u8]) -> Option<usize> {
+        let len = self.len();
+        if out.len() >= len {
+            match *self {
+                Part::Zero(nzeroes) => {
+                    for c in &mut out[..nzeroes] {
+                        *c = b'0';
+                    }
+                }
+                Part::Num(mut v) => {
+                    for c in out[..len].iter_mut().rev() {
+                        *c = b'0' + (v % 10) as u8;
+                        v /= 10;
+                    }
+                }
+                Part::Copy(buf) => {
+                    out[..buf.len()].copy_from_slice(buf);
+                }
+            }
+            Some(len)
+        } else {
+            None
+        }
+    }
+}
+
+/// Formatted result containing one or more parts.
+/// This can be written to the byte buffer or converted to the allocated string.
+#[allow(missing_debug_implementations)]
+#[derive(Clone)]
+pub struct Formatted<'a> {
+    /// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
+    pub sign: &'static str,
+    /// Formatted parts to be rendered after a sign and optional zero padding.
+    pub parts: &'a [Part<'a>],
+}
+
+impl<'a> Formatted<'a> {
+    /// Returns the exact byte length of combined formatted result.
+    pub fn len(&self) -> usize {
+        let mut len = self.sign.len();
+        for part in self.parts {
+            len += part.len();
+        }
+        len
+    }
+
+    /// Writes all formatted parts into the supplied buffer.
+    /// Returns the number of written bytes, or `None` if the buffer is not enough.
+    /// (It may still leave partially written bytes in the buffer; do not rely on that.)
+    pub fn write(&self, out: &mut [u8]) -> Option<usize> {
+        if out.len() < self.sign.len() {
+            return None;
+        }
+        out[..self.sign.len()].copy_from_slice(self.sign.as_bytes());
+
+        let mut written = self.sign.len();
+        for part in self.parts {
+            let len = part.write(&mut out[written..])?;
+            written += len;
+        }
+        Some(written)
+    }
+}
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 6032dc9a2d371..0825abc17ed72 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -29,6 +29,7 @@ pub mod bignum;
 pub mod dec2flt;
 pub mod diy_float;
 pub mod flt2dec;
+pub mod fmt;
 
 #[macro_use]
 mod int_macros; // import int_impl!
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 16051b3bc36c7..d990c48af710a 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -39,6 +39,7 @@
 #![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
+#![feature(numfmt)]
 #![feature(step_trait)]
 #![feature(str_internals)]
 #![feature(test)]
diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
index 960a7ca5ff508..4874e8ec09f8c 100644
--- a/library/core/tests/num/flt2dec/mod.rs
+++ b/library/core/tests/num/flt2dec/mod.rs
@@ -2,10 +2,11 @@ use std::mem::MaybeUninit;
 use std::{fmt, str};
 
 use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
-use core::num::flt2dec::{round_up, Formatted, Part, Sign, MAX_SIG_DIGITS};
+use core::num::flt2dec::{round_up, Sign, MAX_SIG_DIGITS};
 use core::num::flt2dec::{
     to_exact_exp_str, to_exact_fixed_str, to_shortest_exp_str, to_shortest_str,
 };
+use core::num::fmt::{Formatted, Part};
 
 pub use test::Bencher;
 

From ec7292ad3c35b7e3656f90988d9369fd6c55d1c9 Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Sun, 6 Jun 2021 02:28:05 +0100
Subject: [PATCH 2/2] core: add unstable `no_fp_fmt_parse` to disable float
 fmt/parse code

In some projects (e.g. kernel), floating point is forbidden. They can disable
hardware floating point support and use `+soft-float` to avoid fp instructions
from being generated, but as libcore contains the formatting code for `f32`
and `f64`, some fp intrinsics are depended. One could define stubs for these
intrinsics that just panic [1], but it means that if any formatting functions
are accidentally used, mistake can only be caught during the runtime rather
than during compile-time or link-time, and they consume a lot of space without
LTO.

This patch provides an unstable cfg `no_fp_fmt_parse` to disable these.
A panicking stub is still provided for the `Debug` implementation (unfortunately)
because there are some SIMD types that use `#[derive(Debug)]`.

[1]: https://lkml.org/lkml/2021/4/14/1028
---
 library/core/src/fmt/mod.rs                       |  3 +++
 library/core/src/fmt/nofloat.rs                   | 15 +++++++++++++++
 library/core/src/num/mod.rs                       |  5 +++++
 .../core-no-fp-fmt-parse/Makefile                 |  4 ++++
 4 files changed, 27 insertions(+)
 create mode 100644 library/core/src/fmt/nofloat.rs
 create mode 100644 src/test/run-make-fulldeps/core-no-fp-fmt-parse/Makefile

diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 1adfb73ced04d..269963400b624 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -13,7 +13,10 @@ use crate::result;
 use crate::str;
 
 mod builders;
+#[cfg(not(no_fp_fmt_parse))]
 mod float;
+#[cfg(no_fp_fmt_parse)]
+mod nofloat;
 mod num;
 
 #[stable(feature = "fmt_flags_align", since = "1.28.0")]
diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs
new file mode 100644
index 0000000000000..cfb94cd9de530
--- /dev/null
+++ b/library/core/src/fmt/nofloat.rs
@@ -0,0 +1,15 @@
+use crate::fmt::{Debug, Formatter, Result};
+
+macro_rules! floating {
+    ($ty:ident) => {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl Debug for $ty {
+            fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result {
+                panic!("floating point support is turned off");
+            }
+        }
+    };
+}
+
+floating! { f32 }
+floating! { f64 }
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 0825abc17ed72..f60513a5d239a 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -25,9 +25,13 @@ macro_rules! unlikely {
 }
 
 // All these modules are technically private and only exposed for coretests:
+#[cfg(not(no_fp_fmt_parse))]
 pub mod bignum;
+#[cfg(not(no_fp_fmt_parse))]
 pub mod dec2flt;
+#[cfg(not(no_fp_fmt_parse))]
 pub mod diy_float;
+#[cfg(not(no_fp_fmt_parse))]
 pub mod flt2dec;
 pub mod fmt;
 
@@ -44,6 +48,7 @@ mod wrapping;
 pub use wrapping::Wrapping;
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(no_fp_fmt_parse))]
 pub use dec2flt::ParseFloatError;
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/test/run-make-fulldeps/core-no-fp-fmt-parse/Makefile b/src/test/run-make-fulldeps/core-no-fp-fmt-parse/Makefile
new file mode 100644
index 0000000000000..bc4562bef3a96
--- /dev/null
+++ b/src/test/run-make-fulldeps/core-no-fp-fmt-parse/Makefile
@@ -0,0 +1,4 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) --edition=2018 --crate-type=rlib ../../../../library/core/src/lib.rs --cfg no_fp_fmt_parse