Skip to content

Commit 0cf68ed

Browse files
borsgitbot
authored and
gitbot
committed
Auto merge of rust-lang#86048 - nbdd0121:no_floating_point, r=Amanieu
core: add unstable no_fp_fmt_parse to disable float formatting 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
2 parents 6097a92 + 7656be7 commit 0cf68ed

File tree

9 files changed

+156
-121
lines changed

9 files changed

+156
-121
lines changed

Diff for: core/src/fmt/float.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp};
22
use crate::mem::MaybeUninit;
33
use crate::num::flt2dec;
4+
use crate::num::fmt as numfmt;
45

56
// Don't inline this so callers don't use the stack space this function
67
// requires unless they have to.
@@ -15,7 +16,7 @@ where
1516
T: flt2dec::DecodableFloat,
1617
{
1718
let mut buf: [MaybeUninit<u8>; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64
18-
let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 4] = MaybeUninit::uninit_array();
19+
let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = MaybeUninit::uninit_array();
1920
let formatted = flt2dec::to_exact_fixed_str(
2021
flt2dec::strategy::grisu::format_exact,
2122
*num,
@@ -41,7 +42,7 @@ where
4142
{
4243
// enough for f32 and f64
4344
let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array();
44-
let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 4] = MaybeUninit::uninit_array();
45+
let mut parts: [MaybeUninit<numfmt::Part<'_>>; 4] = MaybeUninit::uninit_array();
4546
let formatted = flt2dec::to_shortest_str(
4647
flt2dec::strategy::grisu::format_shortest,
4748
*num,
@@ -85,7 +86,7 @@ where
8586
T: flt2dec::DecodableFloat,
8687
{
8788
let mut buf: [MaybeUninit<u8>; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64
88-
let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 6] = MaybeUninit::uninit_array();
89+
let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = MaybeUninit::uninit_array();
8990
let formatted = flt2dec::to_exact_exp_str(
9091
flt2dec::strategy::grisu::format_exact,
9192
*num,
@@ -112,7 +113,7 @@ where
112113
{
113114
// enough for f32 and f64
114115
let mut buf: [MaybeUninit<u8>; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array();
115-
let mut parts: [MaybeUninit<flt2dec::Part<'_>>; 6] = MaybeUninit::uninit_array();
116+
let mut parts: [MaybeUninit<numfmt::Part<'_>>; 6] = MaybeUninit::uninit_array();
116117
let formatted = flt2dec::to_shortest_exp_str(
117118
flt2dec::strategy::grisu::format_shortest,
118119
*num,

Diff for: core/src/fmt/mod.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ use crate::char::EscapeDebugExtArgs;
77
use crate::iter;
88
use crate::marker::PhantomData;
99
use crate::mem;
10-
use crate::num::flt2dec;
10+
use crate::num::fmt as numfmt;
1111
use crate::ops::Deref;
1212
use crate::result;
1313
use crate::str;
1414

1515
mod builders;
16+
#[cfg(not(no_fp_fmt_parse))]
1617
mod float;
18+
#[cfg(no_fp_fmt_parse)]
19+
mod nofloat;
1720
mod num;
1821

1922
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
@@ -1421,7 +1424,7 @@ impl<'a> Formatter<'a> {
14211424
/// Takes the formatted parts and applies the padding.
14221425
/// Assumes that the caller already has rendered the parts with required precision,
14231426
/// so that `self.precision` can be ignored.
1424-
fn pad_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result {
1427+
fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
14251428
if let Some(mut width) = self.width {
14261429
// for the sign-aware zero padding, we render the sign first and
14271430
// behave as if we had no sign from the beginning.
@@ -1461,14 +1464,14 @@ impl<'a> Formatter<'a> {
14611464
}
14621465
}
14631466

1464-
fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result {
1467+
fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result {
14651468
fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
1466-
// SAFETY: This is used for `flt2dec::Part::Num` and `flt2dec::Part::Copy`.
1467-
// It's safe to use for `flt2dec::Part::Num` since every char `c` is between
1469+
// SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`.
1470+
// It's safe to use for `numfmt::Part::Num` since every char `c` is between
14681471
// `b'0'` and `b'9'`, which means `s` is valid UTF-8.
1469-
// It's also probably safe in practice to use for `flt2dec::Part::Copy(buf)`
1472+
// It's also probably safe in practice to use for `numfmt::Part::Copy(buf)`
14701473
// since `buf` should be plain ASCII, but it's possible for someone to pass
1471-
// in a bad value for `buf` into `flt2dec::to_shortest_str` since it is a
1474+
// in a bad value for `buf` into `numfmt::to_shortest_str` since it is a
14721475
// public function.
14731476
// FIXME: Determine whether this could result in UB.
14741477
buf.write_str(unsafe { str::from_utf8_unchecked(s) })
@@ -1479,7 +1482,7 @@ impl<'a> Formatter<'a> {
14791482
}
14801483
for part in formatted.parts {
14811484
match *part {
1482-
flt2dec::Part::Zero(mut nzeroes) => {
1485+
numfmt::Part::Zero(mut nzeroes) => {
14831486
const ZEROES: &str = // 64 zeroes
14841487
"0000000000000000000000000000000000000000000000000000000000000000";
14851488
while nzeroes > ZEROES.len() {
@@ -1490,7 +1493,7 @@ impl<'a> Formatter<'a> {
14901493
self.buf.write_str(&ZEROES[..nzeroes])?;
14911494
}
14921495
}
1493-
flt2dec::Part::Num(mut v) => {
1496+
numfmt::Part::Num(mut v) => {
14941497
let mut s = [0; 5];
14951498
let len = part.len();
14961499
for c in s[..len].iter_mut().rev() {
@@ -1499,7 +1502,7 @@ impl<'a> Formatter<'a> {
14991502
}
15001503
write_bytes(self.buf, &s[..len])?;
15011504
}
1502-
flt2dec::Part::Copy(buf) => {
1505+
numfmt::Part::Copy(buf) => {
15031506
write_bytes(self.buf, buf)?;
15041507
}
15051508
}

Diff for: core/src/fmt/nofloat.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::fmt::{Debug, Formatter, Result};
2+
3+
macro_rules! floating {
4+
($ty:ident) => {
5+
#[stable(feature = "rust1", since = "1.0.0")]
6+
impl Debug for $ty {
7+
fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result {
8+
panic!("floating point support is turned off");
9+
}
10+
}
11+
};
12+
}
13+
14+
floating! { f32 }
15+
floating! { f64 }

Diff for: core/src/fmt/num.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::fmt;
44
use crate::mem::MaybeUninit;
5-
use crate::num::flt2dec;
5+
use crate::num::fmt as numfmt;
66
use crate::ops::{Div, Rem, Sub};
77
use crate::ptr;
88
use crate::slice;
@@ -406,9 +406,9 @@ macro_rules! impl_Exp {
406406
};
407407

408408
let parts = &[
409-
flt2dec::Part::Copy(buf_slice),
410-
flt2dec::Part::Zero(added_precision),
411-
flt2dec::Part::Copy(exp_slice)
409+
numfmt::Part::Copy(buf_slice),
410+
numfmt::Part::Zero(added_precision),
411+
numfmt::Part::Copy(exp_slice)
412412
];
413413
let sign = if !is_nonnegative {
414414
"-"
@@ -417,7 +417,7 @@ macro_rules! impl_Exp {
417417
} else {
418418
""
419419
};
420-
let formatted = flt2dec::Formatted{sign, parts};
420+
let formatted = numfmt::Formatted{sign, parts};
421421
f.pad_formatted_parts(&formatted)
422422
}
423423

Diff for: core/src/num/flt2dec/mod.rs

+1-101
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ functions.
124124

125125
pub use self::decoder::{decode, DecodableFloat, Decoded, FullDecoded};
126126

127+
use super::fmt::{Formatted, Part};
127128
use crate::mem::MaybeUninit;
128129

129130
pub mod decoder;
@@ -170,107 +171,6 @@ pub fn round_up(d: &mut [u8]) -> Option<u8> {
170171
}
171172
}
172173

173-
/// Formatted parts.
174-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
175-
pub enum Part<'a> {
176-
/// Given number of zero digits.
177-
Zero(usize),
178-
/// A literal number up to 5 digits.
179-
Num(u16),
180-
/// A verbatim copy of given bytes.
181-
Copy(&'a [u8]),
182-
}
183-
184-
impl<'a> Part<'a> {
185-
/// Returns the exact byte length of given part.
186-
pub fn len(&self) -> usize {
187-
match *self {
188-
Part::Zero(nzeroes) => nzeroes,
189-
Part::Num(v) => {
190-
if v < 1_000 {
191-
if v < 10 {
192-
1
193-
} else if v < 100 {
194-
2
195-
} else {
196-
3
197-
}
198-
} else {
199-
if v < 10_000 { 4 } else { 5 }
200-
}
201-
}
202-
Part::Copy(buf) => buf.len(),
203-
}
204-
}
205-
206-
/// Writes a part into the supplied buffer.
207-
/// Returns the number of written bytes, or `None` if the buffer is not enough.
208-
/// (It may still leave partially written bytes in the buffer; do not rely on that.)
209-
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
210-
let len = self.len();
211-
if out.len() >= len {
212-
match *self {
213-
Part::Zero(nzeroes) => {
214-
for c in &mut out[..nzeroes] {
215-
*c = b'0';
216-
}
217-
}
218-
Part::Num(mut v) => {
219-
for c in out[..len].iter_mut().rev() {
220-
*c = b'0' + (v % 10) as u8;
221-
v /= 10;
222-
}
223-
}
224-
Part::Copy(buf) => {
225-
out[..buf.len()].copy_from_slice(buf);
226-
}
227-
}
228-
Some(len)
229-
} else {
230-
None
231-
}
232-
}
233-
}
234-
235-
/// Formatted result containing one or more parts.
236-
/// This can be written to the byte buffer or converted to the allocated string.
237-
#[allow(missing_debug_implementations)]
238-
#[derive(Clone)]
239-
pub struct Formatted<'a> {
240-
/// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
241-
pub sign: &'static str,
242-
/// Formatted parts to be rendered after a sign and optional zero padding.
243-
pub parts: &'a [Part<'a>],
244-
}
245-
246-
impl<'a> Formatted<'a> {
247-
/// Returns the exact byte length of combined formatted result.
248-
pub fn len(&self) -> usize {
249-
let mut len = self.sign.len();
250-
for part in self.parts {
251-
len += part.len();
252-
}
253-
len
254-
}
255-
256-
/// Writes all formatted parts into the supplied buffer.
257-
/// Returns the number of written bytes, or `None` if the buffer is not enough.
258-
/// (It may still leave partially written bytes in the buffer; do not rely on that.)
259-
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
260-
if out.len() < self.sign.len() {
261-
return None;
262-
}
263-
out[..self.sign.len()].copy_from_slice(self.sign.as_bytes());
264-
265-
let mut written = self.sign.len();
266-
for part in self.parts {
267-
let len = part.write(&mut out[written..])?;
268-
written += len;
269-
}
270-
Some(written)
271-
}
272-
}
273-
274174
/// Formats given decimal digits `0.<...buf...> * 10^exp` into the decimal form
275175
/// with at least given number of fractional digits. The result is stored to
276176
/// the supplied parts array and a slice of written parts is returned.

Diff for: core/src/num/fmt.rs

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//! Shared utilties used by both float and integer formatting.
2+
#![doc(hidden)]
3+
#![unstable(
4+
feature = "numfmt",
5+
reason = "internal routines only exposed for testing",
6+
issue = "none"
7+
)]
8+
9+
/// Formatted parts.
10+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
11+
pub enum Part<'a> {
12+
/// Given number of zero digits.
13+
Zero(usize),
14+
/// A literal number up to 5 digits.
15+
Num(u16),
16+
/// A verbatim copy of given bytes.
17+
Copy(&'a [u8]),
18+
}
19+
20+
impl<'a> Part<'a> {
21+
/// Returns the exact byte length of given part.
22+
pub fn len(&self) -> usize {
23+
match *self {
24+
Part::Zero(nzeroes) => nzeroes,
25+
Part::Num(v) => {
26+
if v < 1_000 {
27+
if v < 10 {
28+
1
29+
} else if v < 100 {
30+
2
31+
} else {
32+
3
33+
}
34+
} else {
35+
if v < 10_000 { 4 } else { 5 }
36+
}
37+
}
38+
Part::Copy(buf) => buf.len(),
39+
}
40+
}
41+
42+
/// Writes a part into the supplied buffer.
43+
/// Returns the number of written bytes, or `None` if the buffer is not enough.
44+
/// (It may still leave partially written bytes in the buffer; do not rely on that.)
45+
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
46+
let len = self.len();
47+
if out.len() >= len {
48+
match *self {
49+
Part::Zero(nzeroes) => {
50+
for c in &mut out[..nzeroes] {
51+
*c = b'0';
52+
}
53+
}
54+
Part::Num(mut v) => {
55+
for c in out[..len].iter_mut().rev() {
56+
*c = b'0' + (v % 10) as u8;
57+
v /= 10;
58+
}
59+
}
60+
Part::Copy(buf) => {
61+
out[..buf.len()].copy_from_slice(buf);
62+
}
63+
}
64+
Some(len)
65+
} else {
66+
None
67+
}
68+
}
69+
}
70+
71+
/// Formatted result containing one or more parts.
72+
/// This can be written to the byte buffer or converted to the allocated string.
73+
#[allow(missing_debug_implementations)]
74+
#[derive(Clone)]
75+
pub struct Formatted<'a> {
76+
/// A byte slice representing a sign, either `""`, `"-"` or `"+"`.
77+
pub sign: &'static str,
78+
/// Formatted parts to be rendered after a sign and optional zero padding.
79+
pub parts: &'a [Part<'a>],
80+
}
81+
82+
impl<'a> Formatted<'a> {
83+
/// Returns the exact byte length of combined formatted result.
84+
pub fn len(&self) -> usize {
85+
let mut len = self.sign.len();
86+
for part in self.parts {
87+
len += part.len();
88+
}
89+
len
90+
}
91+
92+
/// Writes all formatted parts into the supplied buffer.
93+
/// Returns the number of written bytes, or `None` if the buffer is not enough.
94+
/// (It may still leave partially written bytes in the buffer; do not rely on that.)
95+
pub fn write(&self, out: &mut [u8]) -> Option<usize> {
96+
if out.len() < self.sign.len() {
97+
return None;
98+
}
99+
out[..self.sign.len()].copy_from_slice(self.sign.as_bytes());
100+
101+
let mut written = self.sign.len();
102+
for part in self.parts {
103+
let len = part.write(&mut out[written..])?;
104+
written += len;
105+
}
106+
Some(written)
107+
}
108+
}

0 commit comments

Comments
 (0)