diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 214d572329ec6..746cddbabd639 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -177,6 +177,15 @@ pub struct Target { pub no_std: bool, } +impl Target { + pub fn from_triple(triple: &str) -> Self { + let mut target: Self = Default::default(); + if triple.contains("-none-") || triple.contains("nvptx") { + target.no_std = true; + } + target + } +} /// Structure of the `config.toml` file that configuration is read from. /// /// This structure uses `Decodable` to automatically decode a TOML configuration @@ -353,6 +362,7 @@ struct TomlTarget { musl_root: Option, wasi_root: Option, qemu_rootfs: Option, + no_std: Option, } impl Config { @@ -595,7 +605,7 @@ impl Config { if let Some(ref t) = toml.target { for (triple, cfg) in t { - let mut target = Target::default(); + let mut target = Target::from_triple(triple); if let Some(ref s) = cfg.llvm_config { target.llvm_config = Some(config.src.join(s)); @@ -606,6 +616,9 @@ impl Config { if let Some(ref s) = cfg.android_ndk { target.ndk = Some(config.src.join(s)); } + if let Some(s) = cfg.no_std { + target.no_std = s; + } target.cc = cfg.cc.clone().map(PathBuf::from); target.cxx = cfg.cxx.clone().map(PathBuf::from); target.ar = cfg.ar.clone().map(PathBuf::from); diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 8ff7056e628f3..530e74da8cac0 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -17,6 +17,7 @@ use std::process::Command; use build_helper::{output, t}; +use crate::config::Target; use crate::Build; struct Finder { @@ -192,13 +193,9 @@ pub fn check(build: &mut Build) { panic!("the iOS target is only supported on macOS"); } - if target.contains("-none-") || target.contains("nvptx") { - if build.no_std(*target).is_none() { - let target = build.config.target_config.entry(target.clone()).or_default(); - - target.no_std = true; - } + build.config.target_config.entry(target.clone()).or_insert(Target::from_triple(target)); + if target.contains("-none-") || target.contains("nvptx") { if build.no_std(*target) == Some(false) { panic!("All the *-none-* and nvptx* targets are no-std targets") } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 8b8bda2e6b44f..9ebb317641875 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1245,6 +1245,38 @@ impl<'b, T: ?Sized> Ref<'b, T> { let borrow = orig.borrow.clone(); (Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow }) } + + /// Convert into a reference to the underlying data. + /// + /// The underlying `RefCell` can never be mutably borrowed from again and will always appear + /// already immutably borrowed. It is not a good idea to leak more than a constant number of + /// references. The `RefCell` can be immutably borrowed again if only a smaller number of leaks + /// have occurred in total. + /// + /// This is an associated function that needs to be used as + /// `Ref::leak(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_leak)] + /// use std::cell::{RefCell, Ref}; + /// let cell = RefCell::new(0); + /// + /// let value = Ref::leak(cell.borrow()); + /// assert_eq!(*value, 0); + /// + /// assert!(cell.try_borrow().is_ok()); + /// assert!(cell.try_borrow_mut().is_err()); + /// ``` + #[unstable(feature = "cell_leak", issue = "69099")] + pub fn leak(orig: Ref<'b, T>) -> &'b T { + // By forgetting this Ref we ensure that the borrow counter in the RefCell never goes back + // to UNUSED again. No further mutable references can be created from the original cell. + mem::forget(orig.borrow); + orig.value + } } #[unstable(feature = "coerce_unsized", issue = "27732")] @@ -1330,6 +1362,37 @@ impl<'b, T: ?Sized> RefMut<'b, T> { let borrow = orig.borrow.clone(); (RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow }) } + + /// Convert into a mutable reference to the underlying data. + /// + /// The underlying `RefCell` can not be borrowed from again and will always appear already + /// mutably borrowed, making the returned reference the only to the interior. + /// + /// This is an associated function that needs to be used as + /// `RefMut::leak(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_leak)] + /// use std::cell::{RefCell, RefMut}; + /// let cell = RefCell::new(0); + /// + /// let value = RefMut::leak(cell.borrow_mut()); + /// assert_eq!(*value, 0); + /// *value = 1; + /// + /// assert!(cell.try_borrow_mut().is_err()); + /// ``` + #[unstable(feature = "cell_leak", issue = "69099")] + pub fn leak(orig: RefMut<'b, T>) -> &'b mut T { + // By forgetting this BorrowRefMut we ensure that the borrow counter in the RefCell never + // goes back to UNUSED again. No further references can be created from the original cell, + // making the current borrow the only reference for the remaining lifetime. + mem::forget(orig.borrow); + orig.value + } } struct BorrowRefMut<'b> { diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 284e94926dc85..5ef673009bb6d 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -29,7 +29,6 @@ where *num, sign, precision, - false, buf.get_mut(), parts.get_mut(), ); @@ -59,7 +58,6 @@ where *num, sign, precision, - false, buf.get_mut(), parts.get_mut(), ); diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 973c2f2b91555..993b1073493e9 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -238,16 +238,8 @@ pub struct Formatter<'a> { // NB. Argument is essentially an optimized partially applied formatting function, // equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. -struct Void { - _priv: (), - /// Erases all oibits, because `Void` erases the type of the object that - /// will be used to produce formatted output. Since we do not know what - /// oibits the real types have (and they can have any or none), we need to - /// take the most conservative approach and forbid all oibits. - /// - /// It was added after #45197 showed that one could share a `!Sync` - /// object across threads by passing it into `format_args!`. - _oibit_remover: PhantomData<*mut dyn Fn()>, +extern "C" { + type Opaque; } /// This struct represents the generic "argument" which is taken by the Xprintf @@ -259,16 +251,23 @@ struct Void { #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[doc(hidden)] pub struct ArgumentV1<'a> { - value: &'a Void, - formatter: fn(&Void, &mut Formatter<'_>) -> Result, + value: &'a Opaque, + formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, } -impl<'a> ArgumentV1<'a> { - #[inline(never)] - fn show_usize(x: &usize, f: &mut Formatter<'_>) -> Result { - Display::fmt(x, f) - } +// This gurantees a single stable value for the function pointer associated with +// indices/counts in the formatting infrastructure. +// +// Note that a function defined as such would not be correct as functions are +// always tagged unnamed_addr with the current lowering to LLVM IR, so their +// address is not considered important to LLVM and as such the as_usize cast +// could have been miscompiled. In practice, we never call as_usize on non-usize +// containing data (as a matter of static generation of the formatting +// arguments), so this is merely an additional check. +#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] +static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |_, _| loop {}; +impl<'a> ArgumentV1<'a> { #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { @@ -278,11 +277,13 @@ impl<'a> ArgumentV1<'a> { #[doc(hidden)] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] pub fn from_usize(x: &usize) -> ArgumentV1<'_> { - ArgumentV1::new(x, ArgumentV1::show_usize) + ArgumentV1::new(x, USIZE_MARKER) } fn as_usize(&self) -> Option { - if self.formatter as usize == ArgumentV1::show_usize as usize { + if self.formatter as usize == USIZE_MARKER as usize { + // SAFETY: The `formatter` field is only set to USIZE_MARKER if + // the value is a usize, so this is safe Some(unsafe { *(self.value as *const _ as *const usize) }) } else { None @@ -1356,11 +1357,11 @@ impl<'a> Formatter<'a> { let mut align = old_align; if self.sign_aware_zero_pad() { // a sign always goes first - let sign = unsafe { str::from_utf8_unchecked(formatted.sign) }; + let sign = formatted.sign; self.buf.write_str(sign)?; // remove the sign from the formatted parts - formatted.sign = b""; + formatted.sign = ""; width = width.saturating_sub(sign.len()); align = rt::v1::Alignment::Right; self.fill = '0'; @@ -1392,7 +1393,7 @@ impl<'a> Formatter<'a> { } if !formatted.sign.is_empty() { - write_bytes(self.buf, formatted.sign)?; + self.buf.write_str(formatted.sign)?; } for part in formatted.parts { match *part { diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index c187471fb5faa..5dfd3a8ecdbd6 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -369,11 +369,11 @@ macro_rules! impl_Exp { flt2dec::Part::Copy(exp_slice) ]; let sign = if !is_nonnegative { - &b"-"[..] + "-" } else if f.sign_plus() { - &b"+"[..] + "+" } else { - &b""[..] + "" }; let formatted = flt2dec::Formatted{sign, parts}; f.pad_formatted_parts(&formatted) diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index 9e760c13c0cf0..f5cd26a1852d6 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -237,7 +237,7 @@ impl<'a> Part<'a> { #[derive(Clone)] pub struct Formatted<'a> { /// A byte slice representing a sign, either `""`, `"-"` or `"+"`. - pub sign: &'static [u8], + pub sign: &'static str, /// Formatted parts to be rendered after a sign and optional zero padding. pub parts: &'a [Part<'a>], } @@ -259,7 +259,7 @@ impl<'a> Formatted<'a> { if out.len() < self.sign.len() { return None; } - out[..self.sign.len()].copy_from_slice(self.sign); + out[..self.sign.len()].copy_from_slice(self.sign.as_bytes()); let mut written = self.sign.len(); for part in self.parts { @@ -402,38 +402,38 @@ pub enum Sign { } /// Returns the static byte string corresponding to the sign to be formatted. -/// It can be either `b""`, `b"+"` or `b"-"`. -fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static [u8] { +/// It can be either `""`, `"+"` or `"-"`. +fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static str { match (*decoded, sign) { - (FullDecoded::Nan, _) => b"", - (FullDecoded::Zero, Sign::Minus) => b"", + (FullDecoded::Nan, _) => "", + (FullDecoded::Zero, Sign::Minus) => "", (FullDecoded::Zero, Sign::MinusRaw) => { if negative { - b"-" + "-" } else { - b"" + "" } } - (FullDecoded::Zero, Sign::MinusPlus) => b"+", + (FullDecoded::Zero, Sign::MinusPlus) => "+", (FullDecoded::Zero, Sign::MinusPlusRaw) => { if negative { - b"-" + "-" } else { - b"+" + "+" } } (_, Sign::Minus) | (_, Sign::MinusRaw) => { if negative { - b"-" + "-" } else { - b"" + "" } } (_, Sign::MinusPlus) | (_, Sign::MinusPlusRaw) => { if negative { - b"-" + "-" } else { - b"+" + "+" } } } @@ -462,7 +462,6 @@ pub fn to_shortest_str<'a, T, F>( v: T, sign: Sign, frac_digits: usize, - _upper: bool, buf: &'a mut [u8], parts: &'a mut [Part<'a>], ) -> Formatted<'a> @@ -679,7 +678,6 @@ pub fn to_exact_fixed_str<'a, T, F>( v: T, sign: Sign, frac_digits: usize, - _upper: bool, buf: &'a mut [u8], parts: &'a mut [Part<'a>], ) -> Formatted<'a> diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index f693504824641..e945d9c4a54ce 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -500,94 +500,91 @@ where { use core::num::flt2dec::Sign::*; - fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize, upper: bool) -> String + fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), { to_string_with_parts(|buf, parts| { - to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, upper, buf, parts) + to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, buf, parts) }) } let f = &mut f_; - assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0, false), "-0"); - assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); - - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0, false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 0, true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0, false), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 0, true), "+inf"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1, true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64, true), "NaN"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1, true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64, true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 0, false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3.14"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3.14"); - assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3.14"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0, false), "-3.14"); - assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.14"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); - assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); - - assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 12, false), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 13, false), "0.0000000000750"); - - assert_eq!(to_string(f, 1.9971e20, Minus, 0, false), "199710000000000000000"); - assert_eq!(to_string(f, 1.9971e20, Minus, 1, false), "199710000000000000000.0"); - assert_eq!(to_string(f, 1.9971e20, Minus, 8, false), "199710000000000000000.00000000"); - - assert_eq!(to_string(f, f32::MAX, Minus, 0, false), format!("34028235{:0>31}", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 1, false), format!("34028235{:0>31}.0", "")); - assert_eq!(to_string(f, f32::MAX, Minus, 8, false), format!("34028235{:0>31}.00000000", "")); + assert_eq!(to_string(f, 0.0, Minus, 0), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 0), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0), "-0"); + assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8), "0.00000000"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "+0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8), "-0.00000000"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 0), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, 0), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3.14"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0), "+3.14"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusRaw, 0), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0), "-3.14"); + assert_eq!(to_string(f, 3.14, Minus, 1), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3), "+3.140"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusRaw, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8), "-3.14000000"); + + assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); + + assert_eq!(to_string(f, 1.9971e20, Minus, 0), "199710000000000000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, 1), "199710000000000000000.0"); + assert_eq!(to_string(f, 1.9971e20, Minus, 8), "199710000000000000000.00000000"); + + assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", "")); let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 0, false), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 45, false), format!("0.{:0>44}1", "")); - assert_eq!(to_string(f, minf32, Minus, 46, false), format!("0.{:0>44}10", "")); + assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", "")); - assert_eq!(to_string(f, f64::MAX, Minus, 0, false), format!("17976931348623157{:0>292}", "")); - assert_eq!(to_string(f, f64::MAX, Minus, 1, false), format!("17976931348623157{:0>292}.0", "")); - assert_eq!( - to_string(f, f64::MAX, Minus, 8, false), - format!("17976931348623157{:0>292}.00000000", "") - ); + assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", "")); + assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", "")); + assert_eq!(to_string(f, f64::MAX, Minus, 8), format!("17976931348623157{:0>292}.00000000", "")); let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 0, false), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 324, false), format!("0.{:0>323}5", "")); - assert_eq!(to_string(f, minf64, Minus, 325, false), format!("0.{:0>323}50", "")); + assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", "")); if cfg!(miri) { // Miri is too slow @@ -595,7 +592,7 @@ where } // very large output - assert_eq!(to_string(f, 1.1, Minus, 80000, false), format!("1.1{:0>79999}", "")); + assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", "")); } pub fn to_shortest_exp_str_test(mut f_: F) @@ -996,166 +993,157 @@ where { use core::num::flt2dec::Sign::*; - fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize, upper: bool) -> String + fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), { to_string_with_parts(|buf, parts| { - to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, upper, buf, parts) + to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, buf, parts) }) } let f = &mut f_; - assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); - assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); - assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); - assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0, false), "-0"); - assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); - assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); - assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); - assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); - assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); - assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); - - assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0, false), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1, true), "inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 8, false), "+inf"); - assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 64, true), "+inf"); - assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1, true), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, false), "NaN"); - assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64, true), "NaN"); - assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1, true), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8, false), "-inf"); - assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64, true), "-inf"); - - assert_eq!(to_string(f, 3.14, Minus, 0, false), "3"); - assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3"); - assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3"); - assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3"); - assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3"); - assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0, false), "-3"); - assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.1"); - assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); - assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); - assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); - assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); - assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); - - assert_eq!(to_string(f, 0.195, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.195, MinusRaw, 0, false), "0"); - assert_eq!(to_string(f, 0.195, MinusPlus, 0, false), "+0"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 0, false), "+0"); - assert_eq!(to_string(f, -0.195, Minus, 0, false), "-0"); - assert_eq!(to_string(f, -0.195, MinusRaw, 0, false), "-0"); - assert_eq!(to_string(f, -0.195, MinusPlus, 0, false), "-0"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 0, false), "-0"); - assert_eq!(to_string(f, 0.195, Minus, 1, true), "0.2"); - assert_eq!(to_string(f, 0.195, MinusRaw, 2, true), "0.20"); - assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+0.195"); - assert_eq!(to_string(f, 0.195, MinusPlusRaw, 4, true), "+0.1950"); - assert_eq!(to_string(f, -0.195, Minus, 5, true), "-0.19500"); - assert_eq!(to_string(f, -0.195, MinusRaw, 6, true), "-0.195000"); - assert_eq!(to_string(f, -0.195, MinusPlus, 7, true), "-0.1950000"); - assert_eq!(to_string(f, -0.195, MinusPlusRaw, 8, true), "-0.19500000"); - - assert_eq!(to_string(f, 999.5, Minus, 0, false), "1000"); - assert_eq!(to_string(f, 999.5, Minus, 1, false), "999.5"); - assert_eq!(to_string(f, 999.5, Minus, 2, false), "999.50"); - assert_eq!(to_string(f, 999.5, Minus, 3, false), "999.500"); - assert_eq!(to_string(f, 999.5, Minus, 30, false), "999.500000000000000000000000000000"); - - assert_eq!(to_string(f, 0.5, Minus, 0, false), "1"); - assert_eq!(to_string(f, 0.5, Minus, 1, false), "0.5"); - assert_eq!(to_string(f, 0.5, Minus, 2, false), "0.50"); - assert_eq!(to_string(f, 0.5, Minus, 3, false), "0.500"); - - assert_eq!(to_string(f, 0.95, Minus, 0, false), "1"); - assert_eq!(to_string(f, 0.95, Minus, 1, false), "0.9"); // because it really is less than 0.95 - assert_eq!(to_string(f, 0.95, Minus, 2, false), "0.95"); - assert_eq!(to_string(f, 0.95, Minus, 3, false), "0.950"); - assert_eq!(to_string(f, 0.95, Minus, 10, false), "0.9500000000"); - assert_eq!(to_string(f, 0.95, Minus, 30, false), "0.949999999999999955591079014994"); - - assert_eq!(to_string(f, 0.095, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.095, Minus, 1, false), "0.1"); - assert_eq!(to_string(f, 0.095, Minus, 2, false), "0.10"); - assert_eq!(to_string(f, 0.095, Minus, 3, false), "0.095"); - assert_eq!(to_string(f, 0.095, Minus, 4, false), "0.0950"); - assert_eq!(to_string(f, 0.095, Minus, 10, false), "0.0950000000"); - assert_eq!(to_string(f, 0.095, Minus, 30, false), "0.095000000000000001110223024625"); - - assert_eq!(to_string(f, 0.0095, Minus, 0, false), "0"); - assert_eq!(to_string(f, 0.0095, Minus, 1, false), "0.0"); - assert_eq!(to_string(f, 0.0095, Minus, 2, false), "0.01"); - assert_eq!(to_string(f, 0.0095, Minus, 3, false), "0.009"); // really is less than 0.0095 - assert_eq!(to_string(f, 0.0095, Minus, 4, false), "0.0095"); - assert_eq!(to_string(f, 0.0095, Minus, 5, false), "0.00950"); - assert_eq!(to_string(f, 0.0095, Minus, 10, false), "0.0095000000"); - assert_eq!(to_string(f, 0.0095, Minus, 30, false), "0.009499999999999999764077607267"); - - assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0"); - assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000"); - assert_eq!(to_string(f, 7.5e-11, Minus, 10, false), "0.0000000001"); - assert_eq!(to_string(f, 7.5e-11, Minus, 11, false), "0.00000000007"); // ditto - assert_eq!(to_string(f, 7.5e-11, Minus, 12, false), "0.000000000075"); - assert_eq!(to_string(f, 7.5e-11, Minus, 13, false), "0.0000000000750"); - assert_eq!(to_string(f, 7.5e-11, Minus, 20, false), "0.00000000007500000000"); - assert_eq!(to_string(f, 7.5e-11, Minus, 30, false), "0.000000000074999999999999999501"); - - assert_eq!(to_string(f, 1.0e25, Minus, 0, false), "10000000000000000905969664"); - assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "10000000000000000905969664.0"); - assert_eq!(to_string(f, 1.0e25, Minus, 3, false), "10000000000000000905969664.000"); - - assert_eq!(to_string(f, 1.0e-6, Minus, 0, false), "0"); - assert_eq!(to_string(f, 1.0e-6, Minus, 3, false), "0.000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 6, false), "0.000001"); - assert_eq!(to_string(f, 1.0e-6, Minus, 9, false), "0.000001000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 12, false), "0.000001000000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 22, false), "0.0000010000000000000000"); - assert_eq!(to_string(f, 1.0e-6, Minus, 23, false), "0.00000099999999999999995"); - assert_eq!(to_string(f, 1.0e-6, Minus, 24, false), "0.000000999999999999999955"); - assert_eq!(to_string(f, 1.0e-6, Minus, 25, false), "0.0000009999999999999999547"); - assert_eq!(to_string(f, 1.0e-6, Minus, 35, false), "0.00000099999999999999995474811182589"); + assert_eq!(to_string(f, 0.0, Minus, 0), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 0), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0), "-0"); + assert_eq!(to_string(f, 0.0, Minus, 1), "0.0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8), "0.00000000"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8), "+0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8), "-0.00000000"); + + assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusRaw, 1), "inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 8), "+inf"); + assert_eq!(to_string(f, 1.0 / 0.0, MinusPlusRaw, 64), "+inf"); + assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusRaw, 1), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8), "NaN"); + assert_eq!(to_string(f, 0.0 / 0.0, MinusPlusRaw, 64), "NaN"); + assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusRaw, 1), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 8), "-inf"); + assert_eq!(to_string(f, -1.0 / 0.0, MinusPlusRaw, 64), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0), "3"); + assert_eq!(to_string(f, 3.14, MinusRaw, 0), "3"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0), "+3"); + assert_eq!(to_string(f, -3.14, Minus, 0), "-3"); + assert_eq!(to_string(f, -3.14, MinusRaw, 0), "-3"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0), "-3"); + assert_eq!(to_string(f, 3.14, Minus, 1), "3.1"); + assert_eq!(to_string(f, 3.14, MinusRaw, 2), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3), "+3.140"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusRaw, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8), "-3.14000000"); + + assert_eq!(to_string(f, 0.195, Minus, 0), "0"); + assert_eq!(to_string(f, 0.195, MinusRaw, 0), "0"); + assert_eq!(to_string(f, 0.195, MinusPlus, 0), "+0"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 0), "+0"); + assert_eq!(to_string(f, -0.195, Minus, 0), "-0"); + assert_eq!(to_string(f, -0.195, MinusRaw, 0), "-0"); + assert_eq!(to_string(f, -0.195, MinusPlus, 0), "-0"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 0), "-0"); + assert_eq!(to_string(f, 0.195, Minus, 1), "0.2"); + assert_eq!(to_string(f, 0.195, MinusRaw, 2), "0.20"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3), "+0.195"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 4), "+0.1950"); + assert_eq!(to_string(f, -0.195, Minus, 5), "-0.19500"); + assert_eq!(to_string(f, -0.195, MinusRaw, 6), "-0.195000"); + assert_eq!(to_string(f, -0.195, MinusPlus, 7), "-0.1950000"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 8), "-0.19500000"); + + assert_eq!(to_string(f, 999.5, Minus, 0), "1000"); + assert_eq!(to_string(f, 999.5, Minus, 1), "999.5"); + assert_eq!(to_string(f, 999.5, Minus, 2), "999.50"); + assert_eq!(to_string(f, 999.5, Minus, 3), "999.500"); + assert_eq!(to_string(f, 999.5, Minus, 30), "999.500000000000000000000000000000"); + + assert_eq!(to_string(f, 0.5, Minus, 0), "1"); + assert_eq!(to_string(f, 0.5, Minus, 1), "0.5"); + assert_eq!(to_string(f, 0.5, Minus, 2), "0.50"); + assert_eq!(to_string(f, 0.5, Minus, 3), "0.500"); + + assert_eq!(to_string(f, 0.95, Minus, 0), "1"); + assert_eq!(to_string(f, 0.95, Minus, 1), "0.9"); // because it really is less than 0.95 + assert_eq!(to_string(f, 0.95, Minus, 2), "0.95"); + assert_eq!(to_string(f, 0.95, Minus, 3), "0.950"); + assert_eq!(to_string(f, 0.95, Minus, 10), "0.9500000000"); + assert_eq!(to_string(f, 0.95, Minus, 30), "0.949999999999999955591079014994"); + + assert_eq!(to_string(f, 0.095, Minus, 0), "0"); + assert_eq!(to_string(f, 0.095, Minus, 1), "0.1"); + assert_eq!(to_string(f, 0.095, Minus, 2), "0.10"); + assert_eq!(to_string(f, 0.095, Minus, 3), "0.095"); + assert_eq!(to_string(f, 0.095, Minus, 4), "0.0950"); + assert_eq!(to_string(f, 0.095, Minus, 10), "0.0950000000"); + assert_eq!(to_string(f, 0.095, Minus, 30), "0.095000000000000001110223024625"); + + assert_eq!(to_string(f, 0.0095, Minus, 0), "0"); + assert_eq!(to_string(f, 0.0095, Minus, 1), "0.0"); + assert_eq!(to_string(f, 0.0095, Minus, 2), "0.01"); + assert_eq!(to_string(f, 0.0095, Minus, 3), "0.009"); // really is less than 0.0095 + assert_eq!(to_string(f, 0.0095, Minus, 4), "0.0095"); + assert_eq!(to_string(f, 0.0095, Minus, 5), "0.00950"); + assert_eq!(to_string(f, 0.0095, Minus, 10), "0.0095000000"); + assert_eq!(to_string(f, 0.0095, Minus, 30), "0.009499999999999999764077607267"); + + assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 10), "0.0000000001"); + assert_eq!(to_string(f, 7.5e-11, Minus, 11), "0.00000000007"); // ditto + assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750"); + assert_eq!(to_string(f, 7.5e-11, Minus, 20), "0.00000000007500000000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 30), "0.000000000074999999999999999501"); + + assert_eq!(to_string(f, 1.0e25, Minus, 0), "10000000000000000905969664"); + assert_eq!(to_string(f, 1.0e25, Minus, 1), "10000000000000000905969664.0"); + assert_eq!(to_string(f, 1.0e25, Minus, 3), "10000000000000000905969664.000"); + + assert_eq!(to_string(f, 1.0e-6, Minus, 0), "0"); + assert_eq!(to_string(f, 1.0e-6, Minus, 3), "0.000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 6), "0.000001"); + assert_eq!(to_string(f, 1.0e-6, Minus, 9), "0.000001000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 12), "0.000001000000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 22), "0.0000010000000000000000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 23), "0.00000099999999999999995"); + assert_eq!(to_string(f, 1.0e-6, Minus, 24), "0.000000999999999999999955"); + assert_eq!(to_string(f, 1.0e-6, Minus, 25), "0.0000009999999999999999547"); + assert_eq!(to_string(f, 1.0e-6, Minus, 35), "0.00000099999999999999995474811182589"); + assert_eq!(to_string(f, 1.0e-6, Minus, 45), "0.000000999999999999999954748111825886258685614"); assert_eq!( - to_string(f, 1.0e-6, Minus, 45, false), - "0.000000999999999999999954748111825886258685614" - ); - assert_eq!( - to_string(f, 1.0e-6, Minus, 55, false), + to_string(f, 1.0e-6, Minus, 55), "0.0000009999999999999999547481118258862586856139387236908" ); assert_eq!( - to_string(f, 1.0e-6, Minus, 65, false), + to_string(f, 1.0e-6, Minus, 65), "0.00000099999999999999995474811182588625868561393872369080781936646" ); assert_eq!( - to_string(f, 1.0e-6, Minus, 75, false), + to_string(f, 1.0e-6, Minus, 75), "0.000000999999999999999954748111825886258685613938723690807819366455078125000" ); - assert_eq!(to_string(f, f32::MAX, Minus, 0, false), "340282346638528859811704183484516925440"); - assert_eq!( - to_string(f, f32::MAX, Minus, 1, false), - "340282346638528859811704183484516925440.0" - ); - assert_eq!( - to_string(f, f32::MAX, Minus, 2, false), - "340282346638528859811704183484516925440.00" - ); + assert_eq!(to_string(f, f32::MAX, Minus, 0), "340282346638528859811704183484516925440"); + assert_eq!(to_string(f, f32::MAX, Minus, 1), "340282346638528859811704183484516925440.0"); + assert_eq!(to_string(f, f32::MAX, Minus, 2), "340282346638528859811704183484516925440.00"); if cfg!(miri) { // Miri is too slow @@ -1163,24 +1151,24 @@ where } let minf32 = ldexp_f32(1.0, -149); - assert_eq!(to_string(f, minf32, Minus, 0, false), "0"); - assert_eq!(to_string(f, minf32, Minus, 1, false), "0.0"); - assert_eq!(to_string(f, minf32, Minus, 2, false), "0.00"); - assert_eq!(to_string(f, minf32, Minus, 4, false), "0.0000"); - assert_eq!(to_string(f, minf32, Minus, 8, false), "0.00000000"); - assert_eq!(to_string(f, minf32, Minus, 16, false), "0.0000000000000000"); - assert_eq!(to_string(f, minf32, Minus, 32, false), "0.00000000000000000000000000000000"); + assert_eq!(to_string(f, minf32, Minus, 0), "0"); + assert_eq!(to_string(f, minf32, Minus, 1), "0.0"); + assert_eq!(to_string(f, minf32, Minus, 2), "0.00"); + assert_eq!(to_string(f, minf32, Minus, 4), "0.0000"); + assert_eq!(to_string(f, minf32, Minus, 8), "0.00000000"); + assert_eq!(to_string(f, minf32, Minus, 16), "0.0000000000000000"); + assert_eq!(to_string(f, minf32, Minus, 32), "0.00000000000000000000000000000000"); assert_eq!( - to_string(f, minf32, Minus, 64, false), + to_string(f, minf32, Minus, 64), "0.0000000000000000000000000000000000000000000014012984643248170709" ); assert_eq!( - to_string(f, minf32, Minus, 128, false), + to_string(f, minf32, Minus, 128), "0.0000000000000000000000000000000000000000000014012984643248170709\ 2372958328991613128026194187651577175706828388979108268586060149" ); assert_eq!( - to_string(f, minf32, Minus, 256, false), + to_string(f, minf32, Minus, 256), "0.0000000000000000000000000000000000000000000014012984643248170709\ 2372958328991613128026194187651577175706828388979108268586060148\ 6638188362121582031250000000000000000000000000000000000000000000\ @@ -1188,7 +1176,7 @@ where ); assert_eq!( - to_string(f, f64::MAX, Minus, 0, false), + to_string(f, f64::MAX, Minus, 0), "1797693134862315708145274237317043567980705675258449965989174768\ 0315726078002853876058955863276687817154045895351438246423432132\ 6889464182768467546703537516986049910576551282076245490090389328\ @@ -1196,7 +1184,7 @@ where 26204144723168738177180919299881250404026184124858368" ); assert_eq!( - to_string(f, f64::MAX, Minus, 10, false), + to_string(f, f64::MAX, Minus, 10), "1797693134862315708145274237317043567980705675258449965989174768\ 0315726078002853876058955863276687817154045895351438246423432132\ 6889464182768467546703537516986049910576551282076245490090389328\ @@ -1205,16 +1193,16 @@ where ); let minf64 = ldexp_f64(1.0, -1074); - assert_eq!(to_string(f, minf64, Minus, 0, false), "0"); - assert_eq!(to_string(f, minf64, Minus, 1, false), "0.0"); - assert_eq!(to_string(f, minf64, Minus, 10, false), "0.0000000000"); + assert_eq!(to_string(f, minf64, Minus, 0), "0"); + assert_eq!(to_string(f, minf64, Minus, 1), "0.0"); + assert_eq!(to_string(f, minf64, Minus, 10), "0.0000000000"); assert_eq!( - to_string(f, minf64, Minus, 100, false), + to_string(f, minf64, Minus, 100), "0.0000000000000000000000000000000000000000000000000000000000000000\ 000000000000000000000000000000000000" ); assert_eq!( - to_string(f, minf64, Minus, 1000, false), + to_string(f, minf64, Minus, 1000), "0.0000000000000000000000000000000000000000000000000000000000000000\ 0000000000000000000000000000000000000000000000000000000000000000\ 0000000000000000000000000000000000000000000000000000000000000000\ @@ -1234,15 +1222,15 @@ where ); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("10.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>80000}", "")); + assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", "")); assert_eq!( - to_string(f, 1.0e-1, Minus, 80000, false), + to_string(f, 1.0e-1, Minus, 80000), format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "") ); assert_eq!( - to_string(f, 1.0e-20, Minus, 80000, false), + to_string(f, 1.0e-20, Minus, 80000), format!( "0.0000000000000000000099999999999999994515327145420957165172950370\ 2787392447107715776066783064379706047475337982177734375{:0>79881}", diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 01fd637b20e66..3dacd2cbe95c8 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -408,20 +408,12 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { { last_source_file } else { - let mut a = 0; - let mut b = imported_source_files.len(); - - while b - a > 1 { - let m = (a + b) / 2; - if imported_source_files[m].original_start_pos > lo { - b = m; - } else { - a = m; - } - } + let index = imported_source_files + .binary_search_by_key(&lo, |source_file| source_file.original_start_pos) + .unwrap_or_else(|index| index - 1); - self.last_source_file_index = a; - &imported_source_files[a] + self.last_source_file_index = index; + &imported_source_files[index] } }; diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index bbfbe9c20df94..d2a6f0b7fcf0c 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -35,61 +35,32 @@ impl<'a> Parser<'a> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - if self.eat_keyword(kw::Let) { - return self.parse_local_mk(lo, attrs.into()).map(Some); - } - if self.is_kw_followed_by_ident(kw::Mut) { - return self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut"); - } - if self.is_kw_followed_by_ident(kw::Auto) { + let stmt = if self.eat_keyword(kw::Let) { + self.parse_local_mk(lo, attrs.into())? + } else if self.is_kw_followed_by_ident(kw::Mut) { + self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")? + } else if self.is_kw_followed_by_ident(kw::Auto) { self.bump(); // `auto` let msg = "write `let` instead of `auto` to introduce a new variable"; - return self.recover_stmt_local(lo, attrs.into(), msg, "let"); - } - if self.is_kw_followed_by_ident(sym::var) { + self.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if self.is_kw_followed_by_ident(sym::var) { self.bump(); // `var` let msg = "write `let` instead of `var` to introduce a new variable"; - return self.recover_stmt_local(lo, attrs.into(), msg, "let"); - } - - // Starts like a simple path, being careful to avoid contextual keywords, - // e.g., `union`, items with `crate` visibility, or `auto trait` items. - // We aim to parse an arbitrary path `a::b` but not something that starts like a path - // (1 token), but it fact not a path. Also, we avoid stealing syntax from `parse_item_`. - if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_path_start_item() + self.recover_stmt_local(lo, attrs.into(), msg, "let")? + } else if self.token.is_path_start() + && !self.token.is_qpath_start() + && !self.is_path_start_item() { - let path = self.parse_path(PathStyle::Expr)?; - - if self.eat(&token::Not) { - return self.parse_stmt_mac(lo, attrs.into(), path); - } - - let expr = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_struct_expr(lo, path, AttrVec::new())? - } else { - let hi = self.prev_span; - self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) - }; - - let expr = self.with_res(Restrictions::STMT_EXPR, |this| { - let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; - this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) - })?; - return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr)))); - } - - // FIXME: Bad copy of attrs - let old_directory_ownership = - mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); - let item = self.parse_item_common(attrs.clone(), false, true, |_| true)?; - self.directory.ownership = old_directory_ownership; - - if let Some(item) = item { - return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))))); - } - - // Do not attempt to parse an expression if we're done here. - if self.token == token::Semi { + // We have avoided contextual keywords like `union`, items with `crate` visibility, + // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something + // that starts like a path (1 token), but it fact not a path. + // Also, we avoid stealing syntax from `parse_item_`. + self.parse_stmt_path_start(lo, attrs)? + } else if let Some(item) = self.parse_stmt_item(attrs.clone())? { + // FIXME: Bad copy of attrs + self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item))) + } else if self.token == token::Semi { + // Do not attempt to parse an expression if we're done here. self.error_outer_attrs(&attrs); self.bump(); let mut last_semi = lo; @@ -104,27 +75,49 @@ impl<'a> Parser<'a> { ExprKind::Tup(Vec::new()), AttrVec::new(), )); - return Ok(Some(self.mk_stmt(lo.to(last_semi), kind))); - } - - if self.token == token::CloseDelim(token::Brace) { + self.mk_stmt(lo.to(last_semi), kind) + } else if self.token != token::CloseDelim(token::Brace) { + // Remainder are line-expr stmts. + let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; + self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) + } else { self.error_outer_attrs(&attrs); return Ok(None); + }; + Ok(Some(stmt)) + } + + fn parse_stmt_item(&mut self, attrs: Vec) -> PResult<'a, Option> { + let old = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); + let item = self.parse_item_common(attrs.clone(), false, true, |_| true)?; + self.directory.ownership = old; + Ok(item) + } + + fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec) -> PResult<'a, Stmt> { + let path = self.parse_path(PathStyle::Expr)?; + + if self.eat(&token::Not) { + return self.parse_stmt_mac(lo, attrs.into(), path); } - // Remainder are line-expr stmts. - let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; - Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)))) + let expr = if self.check(&token::OpenDelim(token::Brace)) { + self.parse_struct_expr(lo, path, AttrVec::new())? + } else { + let hi = self.prev_span; + self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) + }; + + let expr = self.with_res(Restrictions::STMT_EXPR, |this| { + let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; + this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) + })?; + Ok(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr))) } /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. /// At this point, the `!` token after the path has already been eaten. - fn parse_stmt_mac( - &mut self, - lo: Span, - attrs: AttrVec, - path: ast::Path, - ) -> PResult<'a, Option> { + fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> { let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; @@ -145,7 +138,7 @@ impl<'a> Parser<'a> { let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; - Ok(Some(self.mk_stmt(lo.to(hi), kind))) + Ok(self.mk_stmt(lo.to(hi), kind)) } /// Error on outer attributes in this context. @@ -167,12 +160,12 @@ impl<'a> Parser<'a> { attrs: AttrVec, msg: &str, sugg: &str, - ) -> PResult<'a, Option> { + ) -> PResult<'a, Stmt> { let stmt = self.parse_local_mk(lo, attrs)?; self.struct_span_err(lo, "invalid variable declaration") .span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable) .emit(); - Ok(Some(stmt)) + Ok(stmt) } fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> { @@ -372,36 +365,36 @@ impl<'a> Parser<'a> { let mut eat_semi = true; match stmt.kind { - StmtKind::Expr(ref expr) if self.token != token::Eof => { - // expression without semicolon - if classify::expr_requires_semi_to_be_stmt(expr) { - // Just check for errors and recover; do not eat semicolon yet. - if let Err(mut e) = - self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)]) - { - if let TokenKind::DocComment(..) = self.token.kind { - if let Ok(snippet) = self.span_to_snippet(self.token.span) { - let sp = self.token.span; - let marker = &snippet[..3]; - let (comment_marker, doc_comment_marker) = marker.split_at(2); - - e.span_suggestion( - sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), - &format!( - "add a space before `{}` to use a regular comment", - doc_comment_marker, - ), - format!("{} {}", comment_marker, doc_comment_marker), - Applicability::MaybeIncorrect, - ); - } + // Expression without semicolon. + StmtKind::Expr(ref expr) + if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => + { + // Just check for errors and recover; do not eat semicolon yet. + if let Err(mut e) = + self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)]) + { + if let TokenKind::DocComment(..) = self.token.kind { + if let Ok(snippet) = self.span_to_snippet(self.token.span) { + let sp = self.token.span; + let marker = &snippet[..3]; + let (comment_marker, doc_comment_marker) = marker.split_at(2); + + e.span_suggestion( + sp.with_hi(sp.lo() + BytePos(marker.len() as u32)), + &format!( + "add a space before `{}` to use a regular comment", + doc_comment_marker, + ), + format!("{} {}", comment_marker, doc_comment_marker), + Applicability::MaybeIncorrect, + ); } - e.emit(); - self.recover_stmt(); - // Don't complain about type errors in body tail after parse error (#57383). - let sp = expr.span.to(self.prev_span); - stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); } + e.emit(); + self.recover_stmt(); + // Don't complain about type errors in body tail after parse error (#57383). + let sp = expr.span.to(self.prev_span); + stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); } } StmtKind::Local(..) => { diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index be6e41afaf811..c8439764effc3 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -1,34 +1,30 @@ -error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely +error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:8:5 | LL | fn send(_: T) {} | ---- ---- required by this bound in `send` ... LL | send(format_args!("{:?}", c)); - | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` - = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>` - = note: required because it appears within the type `core::fmt::Void` - = note: required because it appears within the type `&core::fmt::Void` + = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = note: required because it appears within the type `&core::fmt::Opaque` = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because of the requirements on the impl of `std::marker::Send` for `&[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `std::fmt::Arguments<'_>` -error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely +error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:9:5 | LL | fn sync(_: T) {} | ---- ---- required by this bound in `sync` ... LL | sync(format_args!("{:?}", c)); - | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` - = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>` - = note: required because it appears within the type `core::fmt::Void` - = note: required because it appears within the type `&core::fmt::Void` + = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = note: required because it appears within the type `&core::fmt::Opaque` = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `&[std::fmt::ArgumentV1<'_>]`