Skip to content
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

Rollup of 6 pull requests #69182

Merged
merged 12 commits into from
Feb 15, 2020
Merged
Show file tree
Hide file tree
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
163 changes: 163 additions & 0 deletions src/libcore/fmt/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use crate::fmt;
use crate::mem::MaybeUninit;
use crate::num::flt2dec;
use crate::ops::{Div, Rem, Sub};
use crate::ptr;
use crate::slice;
Expand Down Expand Up @@ -256,6 +257,161 @@ macro_rules! impl_Display {
};
}

macro_rules! impl_Exp {
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
fn $name(
mut n: $u,
is_nonnegative: bool,
upper: bool,
f: &mut fmt::Formatter<'_>
) -> fmt::Result {
let (mut n, mut exponent, trailing_zeros, added_precision) = {
let mut exponent = 0;
// count and remove trailing decimal zeroes
while n % 10 == 0 && n >= 10 {
n /= 10;
exponent += 1;
}
let trailing_zeros = exponent;

let (added_precision, subtracted_precision) = match f.precision() {
Some(fmt_prec) => {
// number of decimal digits minus 1
let mut tmp = n;
let mut prec = 0;
while tmp >= 10 {
tmp /= 10;
prec += 1;
}
(fmt_prec.saturating_sub(prec), prec.saturating_sub(fmt_prec))
}
None => (0,0)
};
for _ in 1..subtracted_precision {
n/=10;
exponent += 1;
}
if subtracted_precision != 0 {
let rem = n % 10;
n /= 10;
exponent += 1;
// round up last digit
if rem >= 5 {
n += 1;
}
}
(n, exponent, trailing_zeros, added_precision)
};

// 39 digits (worst case u128) + . = 40
let mut buf = [MaybeUninit::<u8>::uninit(); 40];
let mut curr = buf.len() as isize; //index for buf
let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf);
let lut_ptr = DEC_DIGITS_LUT.as_ptr();

// decode 2 chars at a time
while n >= 100 {
let d1 = ((n % 100) as isize) << 1;
curr -= 2;
unsafe {
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
}
n /= 100;
exponent += 2;
}
// n is <= 99, so at most 2 chars long
let mut n = n as isize; // possibly reduce 64bit math
// decode second-to-last character
if n >= 10 {
curr -= 1;
unsafe {
*buf_ptr.offset(curr) = (n as u8 % 10_u8) + b'0';
}
n /= 10;
exponent += 1;
}
// add decimal point iff >1 mantissa digit will be printed
if exponent != trailing_zeros || added_precision != 0 {
curr -= 1;
unsafe {
*buf_ptr.offset(curr) = b'.';
}
}

let buf_slice = unsafe {
// decode last character
curr -= 1;
*buf_ptr.offset(curr) = (n as u8) + b'0';

let len = buf.len() - curr as usize;
slice::from_raw_parts(buf_ptr.offset(curr), len)
};

// stores 'e' (or 'E') and the up to 2-digit exponent
let mut exp_buf = [MaybeUninit::<u8>::uninit(); 3];
let exp_ptr = MaybeUninit::first_ptr_mut(&mut exp_buf);
let exp_slice = unsafe {
*exp_ptr.offset(0) = if upper {b'E'} else {b'e'};
let len = if exponent < 10 {
*exp_ptr.offset(1) = (exponent as u8) + b'0';
2
} else {
let off = exponent << 1;
ptr::copy_nonoverlapping(lut_ptr.offset(off), exp_ptr.offset(1), 2);
3
};
slice::from_raw_parts(exp_ptr, len)
};

let parts = &[
flt2dec::Part::Copy(buf_slice),
flt2dec::Part::Zero(added_precision),
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)
}

$(
#[stable(feature = "integer_exp_format", since = "1.42.0")]
impl fmt::LowerExp for $t {
#[allow(unused_comparisons)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let is_nonnegative = *self >= 0;
let n = if is_nonnegative {
self.$conv_fn()
} else {
// convert the negative num to positive by summing 1 to it's 2 complement
(!self.$conv_fn()).wrapping_add(1)
};
$name(n, is_nonnegative, false, f)
}
})*
$(
#[stable(feature = "integer_exp_format", since = "1.42.0")]
impl fmt::UpperExp for $t {
#[allow(unused_comparisons)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let is_nonnegative = *self >= 0;
let n = if is_nonnegative {
self.$conv_fn()
} else {
// convert the negative num to positive by summing 1 to it's 2 complement
(!self.$conv_fn()).wrapping_add(1)
};
$name(n, is_nonnegative, true, f)
}
})*
};
}

// Include wasm32 in here since it doesn't reflect the native pointer size, and
// often cares strongly about getting a smaller code size.
#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
Expand All @@ -265,13 +421,20 @@ mod imp {
i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
as u64 via to_u64 named fmt_u64
);
impl_Exp!(
i8, u8, i16, u16, i32, u32, i64, u64, usize, isize
as u64 via to_u64 named exp_u64
);
}

#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
mod imp {
use super::*;
impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32);
impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64);
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);
}

impl_Display!(i128, u128 as u128 via to_u128 named fmt_u128);
impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
80 changes: 80 additions & 0 deletions src/libcore/tests/fmt/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ fn test_format_int() {
assert_eq!(format!("{:o}", 1i16), "1");
assert_eq!(format!("{:o}", 1i32), "1");
assert_eq!(format!("{:o}", 1i64), "1");
assert_eq!(format!("{:e}", 1isize), "1e0");
assert_eq!(format!("{:e}", 1i8), "1e0");
assert_eq!(format!("{:e}", 1i16), "1e0");
assert_eq!(format!("{:e}", 1i32), "1e0");
assert_eq!(format!("{:e}", 1i64), "1e0");
assert_eq!(format!("{:E}", 1isize), "1E0");
assert_eq!(format!("{:E}", 1i8), "1E0");
assert_eq!(format!("{:E}", 1i16), "1E0");
assert_eq!(format!("{:E}", 1i32), "1E0");
assert_eq!(format!("{:E}", 1i64), "1E0");

assert_eq!(format!("{}", 1usize), "1");
assert_eq!(format!("{}", 1u8), "1");
Expand Down Expand Up @@ -69,13 +79,79 @@ fn test_format_int() {
assert_eq!(format!("{:o}", 1u16), "1");
assert_eq!(format!("{:o}", 1u32), "1");
assert_eq!(format!("{:o}", 1u64), "1");
assert_eq!(format!("{:e}", 1u8), "1e0");
assert_eq!(format!("{:e}", 1u16), "1e0");
assert_eq!(format!("{:e}", 1u32), "1e0");
assert_eq!(format!("{:e}", 1u64), "1e0");
assert_eq!(format!("{:E}", 1u8), "1E0");
assert_eq!(format!("{:E}", 1u16), "1E0");
assert_eq!(format!("{:E}", 1u32), "1E0");
assert_eq!(format!("{:E}", 1u64), "1E0");

// Test a larger number
assert_eq!(format!("{:b}", 55), "110111");
assert_eq!(format!("{:o}", 55), "67");
assert_eq!(format!("{}", 55), "55");
assert_eq!(format!("{:x}", 55), "37");
assert_eq!(format!("{:X}", 55), "37");
assert_eq!(format!("{:e}", 55), "5.5e1");
assert_eq!(format!("{:E}", 55), "5.5E1");
assert_eq!(format!("{:e}", 10000000000u64), "1e10");
assert_eq!(format!("{:E}", 10000000000u64), "1E10");
assert_eq!(format!("{:e}", 10000000001u64), "1.0000000001e10");
assert_eq!(format!("{:E}", 10000000001u64), "1.0000000001E10");
}

#[test]
fn test_format_int_exp_limits() {
use core::{i128, i16, i32, i64, i8, u128, u16, u32, u64, u8};
assert_eq!(format!("{:e}", i8::MIN), "-1.28e2");
assert_eq!(format!("{:e}", i8::MAX), "1.27e2");
assert_eq!(format!("{:e}", i16::MIN), "-3.2768e4");
assert_eq!(format!("{:e}", i16::MAX), "3.2767e4");
assert_eq!(format!("{:e}", i32::MIN), "-2.147483648e9");
assert_eq!(format!("{:e}", i32::MAX), "2.147483647e9");
assert_eq!(format!("{:e}", i64::MIN), "-9.223372036854775808e18");
assert_eq!(format!("{:e}", i64::MAX), "9.223372036854775807e18");
assert_eq!(format!("{:e}", i128::MIN), "-1.70141183460469231731687303715884105728e38");
assert_eq!(format!("{:e}", i128::MAX), "1.70141183460469231731687303715884105727e38");

assert_eq!(format!("{:e}", u8::MAX), "2.55e2");
assert_eq!(format!("{:e}", u16::MAX), "6.5535e4");
assert_eq!(format!("{:e}", u32::MAX), "4.294967295e9");
assert_eq!(format!("{:e}", u64::MAX), "1.8446744073709551615e19");
assert_eq!(format!("{:e}", u128::MAX), "3.40282366920938463463374607431768211455e38");
}

#[test]
fn test_format_int_exp_precision() {
use core::{i128, i16, i32, i64, i8};

//test that float and integer match
let big_int: u32 = 314_159_265;
assert_eq!(format!("{:.1e}", big_int), format!("{:.1e}", f64::from(big_int)));

//test adding precision
assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
assert_eq!(format!("{:.10e}", i16::MIN), "-3.2768000000e4");
assert_eq!(format!("{:.10e}", i32::MIN), "-2.1474836480e9");
assert_eq!(format!("{:.20e}", i64::MIN), "-9.22337203685477580800e18");
assert_eq!(format!("{:.40e}", i128::MIN), "-1.7014118346046923173168730371588410572800e38");

//test rounding
assert_eq!(format!("{:.1e}", i8::MIN), "-1.3e2");
assert_eq!(format!("{:.1e}", i16::MIN), "-3.3e4");
assert_eq!(format!("{:.1e}", i32::MIN), "-2.1e9");
assert_eq!(format!("{:.1e}", i64::MIN), "-9.2e18");
assert_eq!(format!("{:.1e}", i128::MIN), "-1.7e38");

//test huge precision
assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000)));
//test zero precision
assert_eq!(format!("{:.0e}", 1), format!("1e0",));

//test padding with precision (and sign)
assert_eq!(format!("{:+10.3e}", 1), " +1.000e0");
}

#[test]
Expand All @@ -86,13 +162,17 @@ fn test_format_int_zero() {
assert_eq!(format!("{:o}", 0), "0");
assert_eq!(format!("{:x}", 0), "0");
assert_eq!(format!("{:X}", 0), "0");
assert_eq!(format!("{:e}", 0), "0e0");
assert_eq!(format!("{:E}", 0), "0E0");

assert_eq!(format!("{}", 0u32), "0");
assert_eq!(format!("{:?}", 0u32), "0");
assert_eq!(format!("{:b}", 0u32), "0");
assert_eq!(format!("{:o}", 0u32), "0");
assert_eq!(format!("{:x}", 0u32), "0");
assert_eq!(format!("{:X}", 0u32), "0");
assert_eq!(format!("{:e}", 0u32), "0e0");
assert_eq!(format!("{:E}", 0u32), "0E0");
}

#[test]
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,10 @@ pub fn const_eval_raw_provider<'tcx>(
let cid = key.value;
let def_id = cid.instance.def.def_id();

if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors {
if def_id.is_local()
&& tcx.has_typeck_tables(def_id)
&& tcx.typeck_tables_of(def_id).tainted_by_errors
{
return Err(ErrorHandled::Reported);
}

Expand Down
8 changes: 7 additions & 1 deletion src/librustc_parse/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1832,10 +1832,16 @@ impl<'a> Parser<'a> {
}
}
Err(mut e) => {
e.span_label(struct_sp, "while parsing this struct");
if let Some(f) = recovery_field {
fields.push(f);
e.span_suggestion(
self.prev_span.shrink_to_hi(),
"try adding a comma",
",".into(),
Applicability::MachineApplicable,
);
}
e.span_label(struct_sp, "while parsing this struct");
e.emit();
self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
self.eat(&token::Comma);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2280,7 +2280,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} else if attr.check_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if attr.check_name(sym::track_caller) {
if tcx.fn_sig(id).abi() != abi::Abi::Rust {
if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
Expand All @@ -2301,7 +2301,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.export_name = Some(s);
}
} else if attr.check_name(sym::target_feature) {
if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == Unsafety::Normal {
let msg = "`#[target_feature(..)]` can only be applied to `unsafe` functions";
tcx.sess
.struct_span_err(attr.span, msg)
Expand Down
27 changes: 27 additions & 0 deletions src/libstd/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::fmt::{self, Write};
use crate::io;
use crate::mem;
use crate::memchr;
use crate::num::NonZeroU8;
use crate::ops;
use crate::os::raw::c_char;
use crate::ptr;
Expand Down Expand Up @@ -741,6 +742,32 @@ impl From<Box<CStr>> for CString {
}
}

#[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")]
impl From<Vec<NonZeroU8>> for CString {
/// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without
/// copying nor checking for inner null bytes.
///
/// [`CString`]: ../ffi/struct.CString.html
/// [`NonZeroU8`]: ../num/struct.NonZeroU8.html
/// [`Vec`]: ../vec/struct.Vec.html
#[inline]
fn from(v: Vec<NonZeroU8>) -> CString {
unsafe {
// Transmute `Vec<NonZeroU8>` to `Vec<u8>`.
let v: Vec<u8> = {
// Safety:
// - transmuting between `NonZeroU8` and `u8` is sound;
// - `alloc::Layout<NonZeroU8> == alloc::Layout<u8>`.
let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v);
Vec::from_raw_parts(ptr.cast::<u8>(), len, cap)
};
// Safety: `v` cannot contain null bytes, given the type-level
// invariant of `NonZeroU8`.
CString::from_vec_unchecked(v)
}
}
}

#[stable(feature = "more_box_slice_clone", since = "1.29.0")]
impl Clone for Box<CStr> {
#[inline]
Expand Down
Loading